From 47bc067424c8decb21bf2a45c53a197362e34efa Mon Sep 17 00:00:00 2001 From: GIT Admin Date: Mon, 6 May 2024 18:42:52 +0100 Subject: [PATCH 1/2] Fix receiving in JEELIB_NATIVE mode Fix transmitting to match expected format from EmonHubOEMInterfacer (also matches how transmission has been done before and works with emonglcd) Remove verbose mode and associated Serial.prints to get more room in flash. Verbose mode is spurious as config changes can be verified with 'l' and 'L' options, and was disabled by default. Without removing these there was no room in flash for the code. Consideration could be given in future to make the help more terse and reducing the large amount of Serial.prints uin the code to gain further space --- firmware/emonPi_CM/emonPi_CM.ino | 16 ++- firmware/emonPi_CM/emonPi_CM_config.ino | 174 ++++++++++-------------- 2 files changed, 86 insertions(+), 104 deletions(-) diff --git a/firmware/emonPi_CM/emonPi_CM.ino b/firmware/emonPi_CM/emonPi_CM.ino index a70a068..45042b8 100644 --- a/firmware/emonPi_CM/emonPi_CM.ino +++ b/firmware/emonPi_CM/emonPi_CM.ino @@ -15,7 +15,7 @@ //----------------------------emonPi Firmware Version---------------------------------------------------------------------------------------- */ -const byte firmware_version[3] = {1,1,4}; +const byte firmware_version[3] = {1,1,5}; /* V1.0.0 10/7/2021 Derived from emonLibCM examples and original emonPi sketch, that being derived from https://github.com/openenergymonitor/emonpi/blob/master/Atmega328/emonPi_RFM69CW_RF12Demo_DiscreteSampling @@ -26,6 +26,9 @@ v1.1.2 28/3/2023 Fix missing ACKRequested sendACK v1.1.3 04/4/2023 Updated to use cut down version of RFM69 LowPowerLabs library Updated to match latest EmonLibCM library and emonPiFrontEndCM sketch from Robert v1.1.4 19/4/2023 Faster baud rate 115200 and reduced delay in the main loop to improve radio performance +v1.1.5 06/5/2024 Fix RX print_frame when using JEELIB_NATIVE format + Remove verbose option to give more flash room + Fix TX function to transmit in expected EmonHubOEMInterfacer format emonhub.conf node decoder (assuming Node 5): @@ -56,7 +59,7 @@ emonhub.conf node decoder (assuming Node 5): #include RFM69 radio; #else - #include "spi.h" // Requires "RFM69 Native" JeeLib Driver + //#include "spi.h" // Requires "RFM69 Native" JeeLib Driver #include "rf69.h" RF69 rf; #endif @@ -96,7 +99,6 @@ unsigned long backlightOn; //----------------------------emonPi Settings------------------------------------------------------------------------------------------------ bool debug = true; -bool verbose = false; const unsigned long BAUD_RATE = 115200; @@ -349,7 +351,7 @@ void loop() if ((EEProm.rfOn & RFTX) && outmsgLength) { //if command 'outmsg' is waiting to be sent then let's send it digitalWrite(LEDpin, HIGH); - Serial.print ("Sending ") ; Serial.print((word) outmsgLength); Serial.print(" bytes "); Serial.print("to node " ); Serial.println(txDestId) ; + Serial.print (F("Sending ")) ; Serial.print((word) outmsgLength); Serial.print(F(" bytes to node ") ); Serial.println(txDestId) ; #if RadioFormat == RFM69_LOW_POWER_LABS radio.send(0, (void *)outmsg, outmsgLength); #else @@ -463,7 +465,11 @@ void print_frame(int len) Serial.print(F(" ")); Serial.print(rfInfo.srcNode); // Extract and print node ID Serial.print(F(" ")); + #if RadioFormat == RFM69_LOW_POWER_LABS for (byte i = 0; i < len; ++i) +#else + for (byte i = 2; i < len; ++i) +#endif { Serial.print((word)nativeMsg[i]); Serial.print(F(" ")); @@ -570,7 +576,7 @@ void Startup_to_LCD(int current_lcd_i2c_addr) // Print lcd.clear(); lcd.print(F("Detected: ")); lcd.print(EmonLibCM_getTemperatureSensorCount()); - lcd.setCursor(0, 1); lcd.print(F("DS18B20 Temp")); + lcd.setCursor(0, 1); lcd.print(F("W1 Temp")); delay(2000); lcd.clear(); diff --git a/firmware/emonPi_CM/emonPi_CM_config.ino b/firmware/emonPi_CM/emonPi_CM_config.ino index 6acce14..20ff949 100644 --- a/firmware/emonPi_CM/emonPi_CM_config.ino +++ b/firmware/emonPi_CM/emonPi_CM_config.ino @@ -15,6 +15,8 @@ V1.0.0 10/7/2021 Derived from emonLibCM examples and original emonPi sketch, that being derived from https://github.com/openenergymonitor/emonpi/blob/master/Atmega328/emonPi_RFM69CW_RF12Demo_DiscreteSampling and emonLibCM example sketches, with config input based on emonTx V3 sketches. +v1.1.5 06/5/2024 Remove verbose option to give more flash room + Fix TX function to transmit in expected EmonHubOEMInterfacer format Config functions for emonPiCM @@ -45,7 +47,7 @@ Byte #include // Available Serial Commands -const PROGMEM char helpText1[] = +const PROGMEM char helpText1[] = "|\n" "|Available commands:\n" "| l\t\t- list config (terse)\n" @@ -53,7 +55,6 @@ const PROGMEM char helpText1[] = "| r\t\t- restore defaults & restart\n" "| s\t\t- save to EEPROM\n" "| v\t\t- show version\n" -"| V\t\t- verbose mode, 1 > ON, 0 > OFF\n" "| b\t\t- set r.f. band n = 4 > 433MHz, 8 > 868MHz, 9 > 915MHz (may require hardware change)\n" "| p\t\t- set r.f. power. nn (0 - 31) = -18 dBm to +13 dBm. Default: 25 (+7 dBm)\n" "| g\t- set Group (OEM default = 210)\n" @@ -81,8 +82,8 @@ const PROGMEM char helpText1[] = "|\t\t\tN.B. Sensors CANNOT be added beyond the array size.\n" "| T\\n\t- transmit a string.\n" "| w\t\t- n = 0 > radio OFF, n = 1 for Receive ON, n = 2 for Transmit ON, n = 3 for both ON\n" -"| z\t\t- set the energy values and pulse count(s) to zero\n" -"| ?\t\t- show this again\n|" +"| z\t\t- set energy values and pulse count(s) to zero\n" +"| ?\t\t- help\n|" ; @@ -123,8 +124,7 @@ static void list_calibration(void) Serial.print(F(", period: ")); Serial.println(EEProm.pulse2_period); Serial.print(F("|temp_enable: ")); Serial.print(EEProm.temp_enable); Serial.print(F(", sensors found: ")); Serial.println(EmonLibCM_getTemperatureSensorCount()); - if (verbose) - printTemperatureSensorAddresses(true); + printTemperatureSensorAddresses(true); } static void report_calibration(void) @@ -153,24 +153,15 @@ static void report_calibration(void) static void save_config() { eepromWrite(eepromSig, (byte *)&EEProm, sizeof(EEProm)); - if (verbose) - { - eepromPrint(true); - Serial.println(F("\r\n|Config saved\r\n|")); - } + eepromPrint(true); + Serial.println(F("\r\n|Config saved\r\n|")); } static void wipe_eeprom(void) { - if (verbose) - { - Serial.print(F("|Resetting...")); - } + Serial.print(F("|Resetting...")); eepromHide(eepromSig); - if (verbose) - { - Serial.println(F("|Sketch restarting with default config.")); - } + Serial.println(F("|Restarting with default config.")); } void softReset(void) @@ -198,7 +189,6 @@ void getCalibration(void) int k1; double k2, k3; char c = Serial.peek(); - char* msg; if (!lockout(c)) switch (c) { @@ -206,21 +196,10 @@ void getCalibration(void) case 'a': EEProm.assumedVrms = Serial.parseFloat(); EmonLibCM_setAssumedVrms(EEProm.assumedVrms); - if (verbose) - { - Serial.print(F("|Assumed V: "));Serial.println(EEProm.assumedVrms); - } break; case 'b': // set band: 4 = 433, 8 = 868, 9 = 915 EEProm.RF_freq = bandToFreq(Serial.parseInt()); - if (verbose) - { - Serial.print(F("|RF Band = ")); - if (EEProm.RF_freq == RFM_433MHZ) Serial.println(F("433MHz")); - if (EEProm.RF_freq == RFM_868MHZ) Serial.println(F("868MHz")); - if (EEProm.RF_freq == RFM_915MHZ) Serial.println(F("915MHz")); - } rfChanged = true; break; @@ -247,10 +226,6 @@ void getCalibration(void) k2 = 0.1; EmonLibCM_datalog_period(k2); EEProm.period = k2; - if (verbose) - { - Serial.print(F("|datalog period ")); Serial.print(k2);Serial.println(F(" s")); - } break; case 'f': @@ -259,18 +234,10 @@ void getCalibration(void) */ k1 = Serial.parseFloat(); EEProm.lineFreq = k1; - if (verbose) - { - Serial.print(F("|freq ")); Serial.println(EEProm.lineFreq); - } break; case 'g': // set network group EEProm.networkGroup = Serial.parseInt(); - if (verbose) - { - Serial.print(F("|Group ")); Serial.println(EEProm.networkGroup); - } rfChanged = true; break; @@ -312,10 +279,6 @@ void getCalibration(void) default : ; } - if (verbose) - { - Serial.print(F("|k"));Serial.print(k1);Serial.print(F(" "));Serial.print(k2);Serial.print(F(" "));Serial.println(k3); - } break; case 'L': @@ -357,43 +320,17 @@ void getCalibration(void) EEProm.pulse2_period = k2; break; } - if (verbose) - { - Serial.print(F("|Pulses: ")); - switch (k1) { - case 0 : Serial.println(F("off")); - break; - - case 1 : Serial.print(F("Ch 1: ")); - Serial.print(k2); - Serial.println(F(" ms")); - break; - - case 2 : Serial.print(F("Ch 2: ")); - Serial.print(k2); - Serial.println(F(" ms")); - break; - } - } break; case 'n': case 'i': // Set NodeID - range expected: 1 - 60 EEProm.nodeID = Serial.parseInt(); EEProm.nodeID = constrain(EEProm.nodeID, 1, 63); - if (verbose) - { - Serial.print(F("|Node ")); Serial.println(EEProm.nodeID); - } rfChanged = true; break; case 'p': // set RF power level EEProm.rfPower = (Serial.parseInt() & 0x1F); - if (verbose) - { - Serial.print(F("|p: "));Serial.print((EEProm.rfPower & 0x1F) - 18);Serial.println(F(" dBm")); - } rfChanged = true; break; @@ -412,45 +349,84 @@ void getCalibration(void) set_temperatures(); break; - case 'T': // write alpha-numeric string to be transmitted. - msg = outmsg; - { - char c = 0; - Serial.read(); // discard 'w' - while (c != '\n' && outmsgLength < MAXMSG) - { - c = Serial.read(); - if (c > 31 && c < 127) - { - *msg++ = c; - outmsgLength++; +case 'T': { + + // split the data into its parts + + char *strtokIndx; // this is used by strtok() as an index + char *endofstring; + int numChars = 250; + char receivedChars[numChars]; // enough to receive a CSV line of 62 3-digit values + byte ndx = 0; // Where we are in the receivedChars buffer + unsigned long serTimeout = 100; // 100 msec serial timeout + + receivedChars[0] = '\0'; + Serial.read(); // eat the 'T' + + serTimeout = millis() + serTimeout; + + while (millis() < serTimeout) { + + while (Serial.available() > 0) { + char c = Serial.read(); + if (c != 10 && c != 13) { + receivedChars[ndx] = c; + ndx++; + if (ndx >= numChars) { + // stop buffer overrun + ndx = numChars - 1; } + } else { + serTimeout = millis() - 100; //kill timeout loop + break; } - } - break; + } + } + receivedChars[ndx] = '\0'; + + strtokIndx = strtok(receivedChars, ","); // setup and find the first characters before , or space + while (strtokIndx != NULL && strtokIndx != 0) { + + long txDataByte = strtol(strtokIndx, &endofstring, 10); // convert this part to an integer + if ((endofstring == strtokIndx) || (txDataByte < 0 || txDataByte > 255)) { + Serial.print(F("Tx Data invalid each byte must be between 0 & 255:") ); + Serial.println(F("Usage:T dest,byte1,byteN (Max bytes=60)")); + outmsgLength = 0; // make sure invalid data not sent + break; + } else { + + if (outmsgLength == 0) { + // first byte should be the destination ID, 0 for broadcast + // This doesn't become part of the message + txDestId = txDataByte; + outmsgLength++; + } else { + outmsg[outmsgLength - 1] = txDataByte; // outmsg index is always - 1 due to destID not part of outmsg + outmsgLength++; + } + } + strtokIndx = strtok(NULL, ", "); // get the next characters + } + + if (outmsgLength > 1) { // outmsgLength must be >1, byte1 = destid, byteN=payload + outmsgLength--; // increased above artificially when dealing with txDestId + } else { + outmsgLength = 0; // If we only receive a single byte, we would have destId with no payload + } + + break; + } case 'v': // print firmware version Serial.print(F("|emonPi CM V")); printVersion(); break; - case 'V': // Verbose mode - /* - * Format expected: V0 | V1 - */ - verbose = (bool)Serial.parseInt(); - Serial.print(F("|Verbose mode "));Serial.println(verbose?F("on"):F("off")); - break; - case 'w': /* * Wireless off = 0, tx = 1, rx = 2, tx+rx = 3 * Format expected: w0 - w3 */ EEProm.rfOn = Serial.parseInt(); - if (verbose) - { - Serial.print(F("|Radio "));;Serial.println(EEProm.rfOn); - } break; case 'z': From db4a3dd9b6d3d0e29af1601afbdfc96eb167c8a7 Mon Sep 17 00:00:00 2001 From: GIT Admin Date: Wed, 8 May 2024 14:25:56 +0100 Subject: [PATCH 2/2] Fix MQTT topic selection from config file Format temp and vrms to .2f Allow emonPiLCD1.py to work with both emonlibCM and DS firmware --- lcd/emonPiLCD.cfg | 3 ++- lcd/emonPiLCD1.py | 65 +++++++++++++++++++++++++++-------------------- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/lcd/emonPiLCD.cfg b/lcd/emonPiLCD.cfg index 9abe130..a9d1ce0 100644 --- a/lcd/emonPiLCD.cfg +++ b/lcd/emonPiLCD.cfg @@ -22,11 +22,12 @@ mqtt_user = emonpi mqtt_passwd = emonpimqtt2016 mqtt_host = 127.0.0.1 mqtt_port = 1883 -mqtt_emonpi_topic = emonhub/rx/5/values mqtt_temp1_topic = emon/emonpi/t1 mqtt_temp2_topic = emon/emonpi/t2 mqtt_vrms_topic = emon/emonpi/vrms mqtt_pulse_topic = emon/emonpi/pulsecount +#comment above and uncomment below for CM based firmware +#mqtt_pulse_topic = emon/emonpi/pulse1count mqtt_feed1_topic = emon/emonpi/power1 mqtt_feed2_topic = emon/emonpi/power2 diff --git a/lcd/emonPiLCD1.py b/lcd/emonPiLCD1.py index c8ac749..bfd6bd3 100755 --- a/lcd/emonPiLCD1.py +++ b/lcd/emonPiLCD1.py @@ -40,7 +40,7 @@ mqtt_passwd = config.get('mqtt', 'mqtt_passwd') mqtt_host = config.get('mqtt', 'mqtt_host') mqtt_port = config.getint('mqtt', 'mqtt_port') -mqtt_topics = {config.get('mqtt', 'mqtt_emonpi_topic'): 'basedata', +mqtt_topics = { config.get('mqtt', 'mqtt_temp1_topic'): 'temp1', config.get('mqtt', 'mqtt_temp2_topic'): 'temp2', config.get('mqtt', 'mqtt_feed1_topic'): 'feed1', @@ -252,36 +252,45 @@ def updateLCD(): lcd[1] = feed2_name + ':' + "---" elif page == 4: - basedata = r.get("basedata") - vrms = r.get("vrms") - pulse = r.get("pulse") - if basedata is not None: - basedata = basedata.split(",") - lcd[0] = 'VRMS: ' + basedata[3] + "V" - lcd[1] = 'Pulse: ' + basedata[10] + "p" - elif vrms is not None and pulse is not None: - lcd[0] = 'VRMS: ' + vrms + 'V' + try: + vrmsf = float (r.get('vrms')) + vrmstext = "{vrms:.2f}V" + vrmstext = vrmstext.format(vrms = vrmsf) + pulse = r.get("pulse") + + lcd[0] = 'VRMS: ' + vrmstext lcd[1] = 'Pulse: ' + pulse + 'p' - else: - lcd[0] = 'Connecting...' - lcd[1] = 'Please Wait' - page += 1 + + except: + lcd[0] = 'VRMS: ' + "N/A" + lcd[1] = 'Pulse : ' + "N/A" + logger.error("Error retreiving vrms/pulse or parsing to float .2f") + page +=1 elif page == 5: - basedata = r.get("basedata") - temp1 = r.get('temp1') - temp2 = r.get('temp2') - if basedata is not None: - basedata = basedata.split(",") - lcd[0] = 'Temp 1: ' + basedata[4] + "\0C" - lcd[1] = 'Temp 2: ' + basedata[5] + "\0C" - elif temp1 is not None and temp2 is not None: - lcd[0] = 'Temp 1: ' + temp1 + '\0C' - lcd[1] = 'Temp 2: ' + temp2 + '\0C' - else: - lcd[0] = 'Connecting...' - lcd[1] = 'Please Wait' - page += 1 + try: + temp1f = float (r.get('temp1')) + temp2f = float (r.get('temp2')) + temptext = "{temp:.2f}\0C" + + if ( temp1f == 300 ) : + text1 = "N/A" + else: + text1 = temptext.format(temp = temp1f) + + if ( temp2f == 300 ) : + text2 = "N/A" + else: + text2 = temptext.format(temp = temp2f) + + lcd[0] = 'Temp 1: ' + text1 + lcd[1] = 'Temp 2: ' + text2 + + except: + lcd[0] = 'Temp 1: ' + "N/A" + lcd[1] = 'Temp 2: ' + "N/A" + logger.error("Error retreiving temperatures or parsing to float .2f") + page +=1 elif page == 6: # Get uptime