lynchlab
@aoife_l22 · Mitglied seit April 2025
Engineering student · university
- Themen
- 15
- Antworten
- 79
- Punkte
- 0
Erstellte Forenantworten
Pinning works to get the alarm back today. The proper fix is two lines. paho 2.x wants the callback API version as the first argument, and your script passes the client id there, so „chiller-pi“ gets read as an API version. Change the constructor and the on_connect signature:
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, reason_code, properties):
print("connected:", reason_code)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="chiller-pi")
client.on_connect = on_connect
client.username_pw_set("<ACCESS_TOKEN>") # token as username, empty password
client.tls_set()
client.connect("<device host>", 8883, keepalive=60)
client.loop_start()
...
client.publish("v1/telemetry", json.dumps({"chiller_temp_c": t}), qos=1)
Don’t switch the protocol to MQTT 5 while you’re in there. Hermetry speaks 3.1.1 and refuses an MQTT 5 CONNECT with return code 1. paho still defaults to 3.1.1, so leaving it alone is right.
If the tech had other callbacks (on_disconnect, on_publish), they changed signature in 2.x as well, check the migration notes for each one.
Von English mit KI übersetzt ·
Was passiert mit der laufenden Summe, wenn der Wemos neu startet? Stromausfälle, wenn die Reinigungskräfte den Stecker ziehen, wette ich.
What happens to the running total when the Wemos reboots? Power cuts when the cleaners unplug it, I’d bet.
Then the 2 registers are one 32-bit float. Splitting your reply:
01 slave address
03 function (read holding registers)
04 byte count, 4 bytes follow
43 66 99 9A data: register 0 = 0x4366, register 1 = 0x999A
3A 1E CRC
Put the four data bytes together as 0x4366999A and read them as an IEEE 754 float: sign 0, exponent gives 2^7 = 128, mantissa about 1.8016, and 128 x 1.8016 = 230.6. So Wilson’s 0x4366 is the first half of the float, which is why dividing never comes out right.
On the Uno the bytes arrive most significant first but the AVR is little endian, so reverse them before copying into a float:
uint8_t b[4] = { rx[6], rx[5], rx[4], rx[3] }; // 9A 99 66 43
float v;
memcpy(&v, b, 4);
Serial.print("{"l1.voltage":");
Serial.print(v, 1);
Serial.println("}");
Some meters send the two registers the other way round (word swapped). If you ever get something like 1.2e-23 instead of a voltage, swap rx[3..4] with rx[5..6]. Check the CRC before trusting a reply too.
It’s the timing around DE, I had the exact same thing on a lab rig with an F103.
HAL_UART_Transmit returns when the last byte has gone into the data register, not when it has left the shift register. Then you wait 5 ms on top. At 9600 one byte is about 1 ms, and a fast meter starts answering within a few ms. While DE is high, /RE is high too, so the receiver is off and the first bytes of the reply are gone. And because HAL_UART_Receive is only called after that, anything that came in meanwhile is lost or sits half in the data register.
The echo comes from the other order: if the receive is already armed while you transmit and /RE is low for a moment, you read back your own request.
Drop DE the moment the transmit complete flag (TC) is set, and arm the receive right after:
__HAL_UART_CLEAR_FLAG(&huart2, UART_FLAG_TC);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_UART_Transmit(&huart2, req, 8, 100);
while (!__HAL_UART_GET_FLAG(&huart2, UART_FLAG_TC)) {}
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
__HAL_UART_FLUSH_DRREGISTER(&huart2);
HAL_UART_Receive(&huart2, rx, 9, 200);
Better still, use interrupt or DMA receive with the idle line interrupt, then a 3.5 character gap ends the frame and you don’t need to know the length in advance. The F103 has no hardware DE pin for RS-485, newer families do, which saves all of this.
Went with 100 m of Cat6 on a reel for video and driving, and 868 MHz point-to-point LoRa for telemetry and the e-stop. The base laptop forwards to Hermetry. Pulled the tether out in a test on purpose and the e-stop still worked over LoRa. Judges liked the gas chart.
Kevin is closer. Bluetooth 4.0 is the version of the spec that introduced Low Energy, so „BLE“ is part of 4.0 and every version after it. A „Bluetooth 4.0“ device can be classic Bluetooth, BLE, or both. For battery sensors it’s almost always BLE in practice. Ask the first vendor to confirm in writing.
The bigger question is your second one. Hermetry takes data over MQTT, HTTPS or LoRaWAN, so neither sensor talks to it directly. You’d need a gateway near the motors that listens to the sensors and reports each one as a child device in Hermetry (one gateway login, each sensor shows up as its own device with its own history and alarms). That only works if the vendor documents what the sensor sends: the advertising format, or the BLE characteristics to read. If the data only ever goes into their phone app and they won’t tell you the format, it’s not getting into Hermetry, whatever version it is.
So the question to send both vendors: „Is the data format documented so a third-party BLE gateway can read it?“
Von English mit KI übersetzt ·
Das Gleiche hatte ich im ersten Jahr, der Sensor hat danach funktioniert, aber ich hatte Glück. Komplette Checkliste:Verkabelung: Rot an 3V3 (Pin 1), Schwarz an GND (Pin 6), Gelb an GPIO4 (Pin 7), und ein 4,7k-Widerstand von Gelb nach 3V3. Füge dtoverlay=w1-gpio zu /boot/firmware/config.txt hinzu (oder /boot/config.txt bei älteren Images) und starte neu. Du solltest einen Ordner 28-xxxxxxxxxxxx sehen.Dann das Skript, mit dem paho-Code, den du schon hast:
import glob, json, time
import paho.mqtt.client as mqtt
dev = glob.glob('/sys/bus/w1/devices/28-*/w1_slave')[0]
def read_c():
lines = open(dev).read().splitlines()
if not lines[0].endswith('YES'):
return None # CRC failed, skip this one
return int(lines[1].split('t=')[1]) / 1000.0
c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="basement-pi")
c.username_pw_set("YOUR_ACCESS_TOKEN") # token as username, no password
c.tls_set()
c.connect("YOUR_BROKER_HOST", 8883, keepalive=60)
c.loop_start()
while True:
t = read_c()
if t is not None:
c.publish("v1/telemetry", json.dumps({"temp_c": round(t, 2)}), qos=1)
time.sleep(60)
Verwende einen neuen Schlüsselnamen wie temp_c, damit sich die CPU-Werte nicht mit den anderen im selben Diagramm vermischen. Der Broker-Host steht auf der Karte Connection details des Geräts.
Did the same thing in first year, the probe was fine afterwards but I was lucky. Full checklist:
Wiring: red to 3V3 (pin 1), black to GND (pin 6), yellow to GPIO4 (pin 7), and a 4.7k resistor from yellow to 3V3. Add dtoverlay=w1-gpio to /boot/firmware/config.txt (or /boot/config.txt on older images) and reboot. You should see a 28-xxxxxxxxxxxx folder.
Then the script, on the same paho code you have:
import glob, json, time
import paho.mqtt.client as mqtt
dev = glob.glob('/sys/bus/w1/devices/28-*/w1_slave')[0]
def read_c():
lines = open(dev).read().splitlines()
if not lines[0].endswith('YES'):
return None # CRC failed, skip this one
return int(lines[1].split('t=')[1]) / 1000.0
c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="basement-pi")
c.username_pw_set("YOUR_ACCESS_TOKEN") # token as username, no password
c.tls_set()
c.connect("YOUR_BROKER_HOST", 8883, keepalive=60)
c.loop_start()
while True:
t = read_c()
if t is not None:
c.publish("v1/telemetry", json.dumps({"temp_c": round(t, 2)}), qos=1)
time.sleep(60)
Use a new key name like temp_c so the CPU readings don’t mix into the same chart. Broker host is on the device’s Connection details card.
IPAddress has fromString(), so no splitting needed:
IPAddress ip;
if (ip.fromString(brokerStr)) {
client.setServer(ip, 1883);
}
But Ciaran’s point: for Hermetry you don’t want an IP at all. Its broker is TLS on 8883 and needs SNI, so you must connect by host name. setServer() has a version that takes a host name, which works for your Pi too if you type its name or IP as text:
char brokerHost[64]; // global, lives as long as the program
void applyConfig(const String &s) {
s.toCharArray(brokerHost, sizeof(brokerHost));
client.setServer(brokerHost, 8883);
}
The global buffer is the important bit. PubSubClient keeps the pointer you pass, it doesn’t copy the text. If you pass brokerStr.c_str() from a String that goes out of scope at the end of setup(), the pointer dangles and it’ll try to connect to garbage later. I lost an afternoon to that in my final year project, the board connected on first boot and then never again after a reconnect.
Make the parameter long enough for the Hermetry host on your device’s Connection details card, 64 characters is plenty.
Von English mit KI übersetzt ·
„cmd“ ist SMBus-Bezeichnung. Bei einem SMBus-Blockschreibzugriff heißt das erste Byte nach der Adresse Command-Byte, und bei registerbasierten Chips wie dem ADS1115 ist dieses Byte der Registerzeiger. Ihre erste Zeile setzt den Zeiger also auf das Config-Register (0x01) und schreibt darin 0xC3 und dann 0x83. Auf dem Bus: Start, 0x90, 0x01, 0xC3, 0x83, Stopp.0xC383 bedeutet: eine Einzelwandlung starten, AIN0 gegen GND, Messbereich ±4,096 V, Einzelschussmodus, 128 Samples/s. Das Lesen setzt den Zeiger auf 0x00 (Conversion-Register) und liest zwei Bytes.Ihr Fehler liegt in der Byte-Reihenfolge. Der ADS1115 sendet zuerst das höchstwertige Byte, und das Ergebnis ist vorzeichenbehaftet:
data = bus.read_i2c_block_data(0x48, 0x00, 2)
raw = (data[0] << 8) | data[1]
if raw > 0x7FFF:
raw -= 0x10000
volts = raw * 4.096 / 32768
Bei vertauschten Bytes wird eine kleine Änderung im niederwertigen Byte zu einem riesigen Sprung, und genau das ist Ihr 900 gegenüber 52.000. Für AIN1 ändern Sie die MUX-Bits: [0xD3, 0x83]. Und 10 ms reichen bei 128 SPS aus (eine Wandlung dauert etwa 8 ms), die Wartezeit ist also in Ordnung.
„cmd“ is SMBus naming. In an SMBus block write the first byte after the address is called the command byte, and for register-based chips like the ADS1115 that byte is the register pointer. So your first line puts the pointer on the Config register (0x01) and writes 0xC3 then 0x83 into it. On the wire: start, 0x90, 0x01, 0xC3, 0x83, stop.
0xC383 means: start a single conversion, AIN0 against GND, ±4.096 V range, single-shot mode, 128 samples/s. The read sets the pointer to 0x00 (Conversion register) and reads two bytes.
Your bug is the byte order. The ADS1115 sends the most significant byte first, and the result is signed:
data = bus.read_i2c_block_data(0x48, 0x00, 2)
raw = (data[0] << 8) | data[1]
if raw > 0x7FFF:
raw -= 0x10000
volts = raw * 4.096 / 32768
With the bytes swapped, a small change in the low byte becomes a huge jump, which is your 900 vs 52,000. For AIN1 change the MUX bits: [0xD3, 0x83]. And 10 ms is enough at 128 SPS (one conversion is about 8 ms), so the sleep is fine.
I did a tracker board for my RF module last year and got the same „slow fix, half range“ result on rev A, so this is mostly what my lecturer took apart on it.
Keep the top pour, but make it a real ground: connected to the layer 2 plane with stitching vias everywhere, especially along every RF trace and around each RF section. Space them about 3 to 5 mm apart, tighter near the RF parts. A pour with a few random vias is a floating patch that resonates, and that alone can cost you sensitivity.
Do not split the ground. Isolate the sections by placement (each radio in its own corner, the noisy LTE power stuff away from GNSS) and, if needed, by a stitched fence of vias, but keep one continuous plane underneath.
Under and around the chip antenna and the patch: follow each antenna’s datasheet keep-out exactly. No copper on any layer in the chip antenna’s keep-out, and the patch wants its specified ground area under it. Michael is right too: give the two antennas different edges and ideally opposite corners.
Run your RF traces as grounded coplanar waveguide at 50 ohms (calculate with your stack-up, the vias on both sides are part of it) and leave a pi-network footprint at each antenna feed so you can tune later.
Then measure: send the LoRa RSSI and SNR and the GNSS satellite count and time to fix as readings with every message, and compare rev A against rev B on one chart. That’s the easiest A/B test you’ll get.
Von English mit KI übersetzt ·
Und bei den 12 Steckdosen sollten Sie die Nachrichten auch auf der Gateway-Seite bündeln. Eine einzelne v1/gw/telemetry-Nachricht kann alle davon enthalten, geschlüsselt nach Kindname.
And for the 12 plugs, batch them on the gateway side too. One v1/gw/telemetry message can carry all of them, keyed by child name.
Von English mit KI übersetzt ·
Ja. Dieser Blog ist für einen Broker in Ihrem eigenen Heimnetz gedacht, deshalb steht dort eine 192.168-Adresse. Für Hermetry sollten Sie überhaupt keine IP verwenden: Verbinden Sie sich über den Host-Namen aus der Karte Connection details, TLS auf 8883. TLS benötigt den Namen (SNI), deshalb schlägt die angepingte IP fehl, und einfaches 1883 wird abgelehnt, sofern das Profil kein unverschlüsseltes MQTT erlaubt, was standardmäßig nicht der Fall ist. rc=5 bedeutet „not authorised“, der eigentliche Grund landet im Tab Log des Geräts, das lohnt einen Blick.
import ssl, json, paho.mqtt.client as mqtt
HOST = "<host from Connection details>"
TOKEN = "<access token>"
c = mqtt.Client(client_id="reefer-01")
c.username_pw_set(TOKEN) # token as username, no password
c.tls_set(cert_reqs=ssl.CERT_REQUIRED) # normal public CA bundle
c.connect(HOST, 8883, keepalive=60)
c.loop_start()
c.publish("v1/telemetry", json.dumps({"temperature": -18.2}), qos=1)
Mit paho 2.x müssen Sie stattdessen mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="reefer-01") verwenden.
Yes. That blog is for a broker on your own home network, that’s why it has a 192.168 address. For Hermetry there’s no IP you should use at all: connect by the host name from the Connection details card, TLS on 8883. TLS needs the name (SNI), so the pinged IP fails, and plain 1883 is refused unless the profile allows plain MQTT, which it doesn’t by default. rc=5 is „not authorised“, and the actual reason ends up on the device’s Log tab, worth a look.
import ssl, json, paho.mqtt.client as mqtt
HOST = "<host from Connection details>"
TOKEN = "<access token>"
c = mqtt.Client(client_id="reefer-01")
c.username_pw_set(TOKEN) # token as username, no password
c.tls_set(cert_reqs=ssl.CERT_REQUIRED) # normal public CA bundle
c.connect(HOST, 8883, keepalive=60)
c.loop_start()
c.publish("v1/telemetry", json.dumps({"temperature": -18.2}), qos=1)
With paho 2.x you need mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="reefer-01") instead.
Von English mit KI übersetzt ·
Das hat funktioniert, alle 12 sind online. Ich bin sofort auf das device_exists-Problem gestoßen, weil ich beim Debuggen den Flash von Knoten 3 gelöscht hatte; er war bereits als aq-3c84a1 registriert. Ich habe das Gerät in der Konsole gelöscht, danach wurde es problemlos neu provisioniert. Heute Morgen habe ich alle aus der Quarantäne aktiviert. Außerdem musste ich die Anführungszeichen richtig escapen, meine erste Version hat fehlerhaftes JSON gesendet und ich habe einfach keine Antwort bekommen.
That worked, all 12 are up. I did hit the device_exists thing straight away because I’d erased flash on node 3 while debugging, it had already registered as aq-3c84a1. Deleted that device in the console and it provisioned again fine. Activated them all from quarantine this morning. Also had to escape the quotes properly, my first version sent broken JSON and just got nothing back.
Von English mit KI übersetzt ·
Arduino-Core 2.0.14 in PlatformIO. Ich bleibe gern bei WiFiManager für den Wi-Fi-Teil, hänge aber am Hermetry-Token. Ich möchte auch nicht die Konsole öffnen, 12 Geräte anlegen und 12 Token in 12 Portale kopieren, wenn ich das vermeiden kann.
Arduino core 2.0.14 in PlatformIO. Happy to stay with WiFiManager for the Wi-Fi bit, it’s the Hermetry token I’m stuck on. I don’t want to open the console and create 12 devices and copy 12 tokens into 12 portals either if I can avoid it.
Von English mit KI übersetzt ·
Das war es, die disable-bt-Zeile aus dem Druckerprojekt. Peinlich. Auskommentiert, hciuart aktiviert, hci0 ist wieder da und alle sechs Tags tauchen im Scan auf. Sie werden jetzt als Untergeordnete in Hermetry angezeigt.
That was it, the disable-bt line from the printer project. Embarrassing. Commented out, hciuart enabled, hci0 is back and all six tags show up in the scan. They’re appearing as children in Hermetry now.

