From 9ffed7bbc8812b125637fe69c466c956750cde1c Mon Sep 17 00:00:00 2001 From: Keith Chiem Date: Wed, 29 Sep 2021 02:30:59 -0700 Subject: [PATCH 1/6] move constant declarations outside the function calls, no need to re-run them for each call. --- sources/inverter-mqtt/mqtt-push.sh | 32 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/sources/inverter-mqtt/mqtt-push.sh b/sources/inverter-mqtt/mqtt-push.sh index 5b1002c..a143594 100755 --- a/sources/inverter-mqtt/mqtt-push.sh +++ b/sources/inverter-mqtt/mqtt-push.sh @@ -1,14 +1,24 @@ #!/bin/bash + +MQTT_SERVER=`cat /etc/inverter/mqtt.json | jq '.server' -r` +MQTT_PORT=`cat /etc/inverter/mqtt.json | jq '.port' -r` +MQTT_TOPIC=`cat /etc/inverter/mqtt.json | jq '.topic' -r` +MQTT_DEVICENAME=`cat /etc/inverter/mqtt.json | jq '.devicename' -r` +MQTT_USERNAME=`cat /etc/inverter/mqtt.json | jq '.username' -r` +MQTT_PASSWORD=`cat /etc/inverter/mqtt.json | jq '.password' -r` + INFLUX_ENABLED=`cat /etc/inverter/mqtt.json | jq '.influx.enabled' -r` +if [[ $INFLUX_ENABLED == "true" ]] ; then + INFLUX_HOST=`cat /etc/inverter/mqtt.json | jq '.influx.host' -r` + INFLUX_USERNAME=`cat /etc/inverter/mqtt.json | jq '.influx.username' -r` + INFLUX_PASSWORD=`cat /etc/inverter/mqtt.json | jq '.influx.password' -r` + INFLUX_DEVICE=`cat /etc/inverter/mqtt.json | jq '.influx.device' -r` + INFLUX_PREFIX=`cat /etc/inverter/mqtt.json | jq '.influx.prefix' -r` + INFLUX_DATABASE=`cat /etc/inverter/mqtt.json | jq '.influx.database' -r` + INFLUX_MEASUREMENT_NAME=`cat /etc/inverter/mqtt.json | jq '.influx.namingMap.'$1'' -r` +fi pushMQTTData () { - MQTT_SERVER=`cat /etc/inverter/mqtt.json | jq '.server' -r` - MQTT_PORT=`cat /etc/inverter/mqtt.json | jq '.port' -r` - MQTT_TOPIC=`cat /etc/inverter/mqtt.json | jq '.topic' -r` - MQTT_DEVICENAME=`cat /etc/inverter/mqtt.json | jq '.devicename' -r` - MQTT_USERNAME=`cat /etc/inverter/mqtt.json | jq '.username' -r` - MQTT_PASSWORD=`cat /etc/inverter/mqtt.json | jq '.password' -r` - mosquitto_pub \ -h $MQTT_SERVER \ -p $MQTT_PORT \ @@ -23,14 +33,6 @@ pushMQTTData () { } pushInfluxData () { - INFLUX_HOST=`cat /etc/inverter/mqtt.json | jq '.influx.host' -r` - INFLUX_USERNAME=`cat /etc/inverter/mqtt.json | jq '.influx.username' -r` - INFLUX_PASSWORD=`cat /etc/inverter/mqtt.json | jq '.influx.password' -r` - INFLUX_DEVICE=`cat /etc/inverter/mqtt.json | jq '.influx.device' -r` - INFLUX_PREFIX=`cat /etc/inverter/mqtt.json | jq '.influx.prefix' -r` - INFLUX_DATABASE=`cat /etc/inverter/mqtt.json | jq '.influx.database' -r` - INFLUX_MEASUREMENT_NAME=`cat /etc/inverter/mqtt.json | jq '.influx.namingMap.'$1'' -r` - curl -i -XPOST "$INFLUX_HOST/write?db=$INFLUX_DATABASE&precision=s" -u "$INFLUX_USERNAME:$INFLUX_PASSWORD" --data-binary "$INFLUX_PREFIX,device=$INFLUX_DEVICE $INFLUX_MEASUREMENT_NAME=$2" } From 73aa98678cf7d33dc008a2d6e54d079ce67e389c Mon Sep 17 00:00:00 2001 From: Keith Chiem Date: Sat, 2 Oct 2021 02:08:39 -0700 Subject: [PATCH 2/6] - loop the subscriber process to handle mqtt server restarts - reduce unnecessary wrapper processes --- sources/inverter-mqtt/entrypoint.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sources/inverter-mqtt/entrypoint.sh b/sources/inverter-mqtt/entrypoint.sh index a459cd3..85ef711 100755 --- a/sources/inverter-mqtt/entrypoint.sh +++ b/sources/inverter-mqtt/entrypoint.sh @@ -6,10 +6,11 @@ export TERM=xterm # Init the mqtt server for the first time, then every 5 minutes # This will re-create the auto-created topics in the MQTT server if HA is restarted... -watch -n 300 /opt/inverter-mqtt/mqtt-init.sh > /dev/null 2>&1 & +watch -xn 300 /opt/inverter-mqtt/mqtt-init.sh & # Run the MQTT Subscriber process in the background (so that way we can change the configuration on the inverter from home assistant) -/opt/inverter-mqtt/mqtt-subscriber.sh & +# This normally doesn't exit, but the watch is needed to handle mqtt server restarts. +watch -xn 1 /opt/inverter-mqtt/mqtt-subscriber.sh & # execute exactly every 30 seconds... -watch -n 30 /opt/inverter-mqtt/mqtt-push.sh > /dev/null 2>&1 +watch -xn 30 /opt/inverter-mqtt/mqtt-push.sh From 7dd92830164ca242c7cba5a459ad44923af2094a Mon Sep 17 00:00:00 2001 From: Keith Chiem Date: Sat, 2 Oct 2021 02:10:22 -0700 Subject: [PATCH 3/6] change temperature icon --- sources/inverter-mqtt/mqtt-init.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/inverter-mqtt/mqtt-init.sh b/sources/inverter-mqtt/mqtt-init.sh index e9e6197..e03b9b2 100755 --- a/sources/inverter-mqtt/mqtt-init.sh +++ b/sources/inverter-mqtt/mqtt-init.sh @@ -52,7 +52,7 @@ registerTopic "Load_watt" "W" "chart-bell-curve" registerTopic "Load_watthour" "Wh" "chart-bell-curve" registerTopic "Load_va" "VA" "chart-bell-curve" registerTopic "Bus_voltage" "V" "details" -registerTopic "Heatsink_temperature" "" "details" +registerTopic "Heatsink_temperature" "C" "thermometer" registerTopic "Battery_capacity" "%" "battery-outline" registerTopic "Battery_voltage" "V" "battery-outline" registerTopic "Battery_charge_current" "A" "current-dc" From be2d786cb30bbd7c3ad6a17cf4a0f892d60432da Mon Sep 17 00:00:00 2001 From: Keith Chiem Date: Sat, 2 Oct 2021 02:10:41 -0700 Subject: [PATCH 4/6] update mqtt immediately after running a command --- sources/inverter-mqtt/mqtt-subscriber.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/sources/inverter-mqtt/mqtt-subscriber.sh b/sources/inverter-mqtt/mqtt-subscriber.sh index f30ce27..0e28ef0 100755 --- a/sources/inverter-mqtt/mqtt-subscriber.sh +++ b/sources/inverter-mqtt/mqtt-subscriber.sh @@ -12,5 +12,6 @@ do echo "Incoming request send: [$rawcmd] to inverter." /opt/inverter-cli/bin/inverter_poller -r $rawcmd; + /opt/inverter-mqtt/mqtt-push.sh done < <(mosquitto_sub -h $MQTT_SERVER -p $MQTT_PORT -u "$MQTT_USERNAME" -P "$MQTT_PASSWORD" -t "$MQTT_TOPIC/sensor/$MQTT_DEVICENAME" -q 1) From 3b3c67c0348aad7c3aa8b55dcf1613268f66d9c0 Mon Sep 17 00:00:00 2001 From: Keith Chiem Date: Sat, 2 Oct 2021 05:10:06 -0700 Subject: [PATCH 5/6] - @nrm21 inspired changes--allows sending commands longer than 5 bytes and removes the need to provide qpiri/qpiws/qmod/qpigs reply sizes in the config. - also fixed some compiler warnings. --- sources/inverter-cli/inverter.cpp | 61 +++++++++++++++++++++---------- sources/inverter-cli/inverter.h | 4 +- sources/inverter-cli/main.cpp | 11 +----- 3 files changed, 44 insertions(+), 32 deletions(-) diff --git a/sources/inverter-cli/inverter.cpp b/sources/inverter-cli/inverter.cpp index 45711f4..cd910f1 100644 --- a/sources/inverter-cli/inverter.cpp +++ b/sources/inverter-cli/inverter.cpp @@ -9,16 +9,12 @@ #include #include -cInverter::cInverter(std::string devicename, int qpiri, int qpiws, int qmod, int qpigs) { +cInverter::cInverter(std::string devicename) { device = devicename; status1[0] = 0; status2[0] = 0; warnings[0] = 0; mode = 0; - qpiri = qpiri; - qpiws = qpiws; - qmod = qmod; - qpigs = qpigs; } string *cInverter::GetQpigsStatus() { @@ -68,7 +64,7 @@ int cInverter::GetMode() { return result; } -bool cInverter::query(const char *cmd, int replysize) { +bool cInverter::query(const char *cmd) { time_t started; int fd; int i=0, n; @@ -109,14 +105,35 @@ bool cInverter::query(const char *cmd, int replysize) { buf[n++] = crc >> 8; buf[n++] = crc & 0xff; - buf[n++] = 0x0d; + buf[n++] = 0x0d; // '\r' + buf[n+1] = '\0'; // see workaround below + + // send a command + int chunk_size = 8; + for (int offset = 0; offset < n; usleep(50000)) { + int left = n - offset; + int towrite = left > chunk_size ? chunk_size : left; + // WORKAROUND: For some reason, writing 1 byte causes it to error. + // However, since we padded with '\0' above, we can give it 2 instead. + // I don't know of any 6 (+ 2*CRC + '\r') byte commnads to test it on + // but this at least gets it to return NAK. + if (towrite == 1) towrite = 2; + //lprintf("DEBUG: offset %d, writing %d", offset, towrite); + ssize_t written = write(fd, &buf[offset], towrite); + if (written > 0) + offset += written; + else { + lprintf("INVERTER: command write failed (written=%d, errno=%d: %s)", written, errno, strerror(errno)); + break; + } + //lprintf("DEBUG: %d bytes to write, %d bytes written", n, offset); + } - //send a command - write(fd, &buf, n); + char *startbuf = 0; + char *endbuf = 0; time(&started); - do { - n = read(fd, (void*)buf+i, replysize-i); + n = read(fd, &buf[i], 120-i); if (n < 0) { if (time(NULL) - started > 2) { lprintf("INVERTER: %s read timeout", cmd); @@ -128,10 +145,14 @@ bool cInverter::query(const char *cmd, int replysize) { } i += n; - } while (i (%d bytes)", cmd, i); return false; } } @@ -163,7 +184,7 @@ void cInverter::poll() { // Reading mode if (!ups_qmod_changed) { - if (query("QMOD", qmod)) { + if (query("QMOD")) { SetMode(buf[1]); ups_qmod_changed = true; } @@ -171,7 +192,7 @@ void cInverter::poll() { // reading status (QPIGS) if (!ups_qpigs_changed) { - if (query("QPIGS", qpigs)) { + if (query("QPIGS")) { m.lock(); strcpy(status1, (const char*)buf+1); m.unlock(); @@ -181,7 +202,7 @@ void cInverter::poll() { // Reading QPIRI status if (!ups_qpiri_changed) { - if (query("QPIRI", qpiri)) { + if (query("QPIRI")) { m.lock(); strcpy(status2, (const char*)buf+1); m.unlock(); @@ -191,7 +212,7 @@ void cInverter::poll() { // Get any device warnings... if (!ups_qpiws_changed) { - if (query("QPIWS", qpiws)) { + if (query("QPIWS")) { m.lock(); strcpy(warnings, (const char*)buf+1); m.unlock(); @@ -205,7 +226,7 @@ void cInverter::poll() { void cInverter::ExecuteCmd(const string cmd) { // Sending any command raw - if (query(cmd.data(), 7)) { + if (query(cmd.data())) { m.lock(); strcpy(status2, (const char*)buf+1); m.unlock(); diff --git a/sources/inverter-cli/inverter.h b/sources/inverter-cli/inverter.h index 3501b6b..f406599 100644 --- a/sources/inverter-cli/inverter.h +++ b/sources/inverter-cli/inverter.h @@ -19,11 +19,11 @@ class cInverter { void SetMode(char newmode); bool CheckCRC(unsigned char *buff, int len); - bool query(const char *cmd, int replysize); + bool query(const char *cmd); uint16_t cal_crc_half(uint8_t *pin, uint8_t len); public: - cInverter(std::string devicename, int qpiri, int qpiws, int qmod, int qpigs); + cInverter(std::string devicename); void poll(); void runMultiThread() { std::thread t1(&cInverter::poll, this); diff --git a/sources/inverter-cli/main.cpp b/sources/inverter-cli/main.cpp index 7650fab..8802e87 100644 --- a/sources/inverter-cli/main.cpp +++ b/sources/inverter-cli/main.cpp @@ -43,7 +43,6 @@ string devicename; int runinterval; float ampfactor; float wattfactor; -int qpiri, qpiws, qmod, qpigs; // --------------------------------------- @@ -91,14 +90,6 @@ void getSettingsFile(string filename) { attemptAddSetting(&wattfactor, linepart2); else if(linepart1 == "watt_factor") attemptAddSetting(&wattfactor, linepart2); - else if(linepart1 == "qpiri") - attemptAddSetting(&qpiri, linepart2); - else if(linepart1 == "qpiws") - attemptAddSetting(&qpiws, linepart2); - else if(linepart1 == "qmod") - attemptAddSetting(&qmod, linepart2); - else if(linepart1 == "qpigs") - attemptAddSetting(&qpigs, linepart2); else continue; } @@ -180,7 +171,7 @@ int main(int argc, char* argv[]) { } bool ups_status_changed(false); - ups = new cInverter(devicename,qpiri,qpiws,qmod,qpigs); + ups = new cInverter(devicename); // Logic to send 'raw commands' to the inverter.. if (!rawcmd.empty()) { From a609f96f817288cf281a5e19f48e824ed54d4e9a Mon Sep 17 00:00:00 2001 From: Keith Chiem Date: Sat, 2 Oct 2021 05:32:37 -0700 Subject: [PATCH 6/6] fix typo --- sources/inverter-cli/inverter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/inverter-cli/inverter.cpp b/sources/inverter-cli/inverter.cpp index cd910f1..ef0218b 100644 --- a/sources/inverter-cli/inverter.cpp +++ b/sources/inverter-cli/inverter.cpp @@ -115,7 +115,7 @@ bool cInverter::query(const char *cmd) { int towrite = left > chunk_size ? chunk_size : left; // WORKAROUND: For some reason, writing 1 byte causes it to error. // However, since we padded with '\0' above, we can give it 2 instead. - // I don't know of any 6 (+ 2*CRC + '\r') byte commnads to test it on + // I don't know of any 6 (+ 2*CRC + '\r') byte commands to test it on // but this at least gets it to return NAK. if (towrite == 1) towrite = 2; //lprintf("DEBUG: offset %d, writing %d", offset, towrite);