From 45efb6509ca9435f7851816fbe2fb1f6d44ebfe1 Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Wed, 22 Mar 2023 14:51:40 +0000 Subject: [PATCH 1/8] improved mqtt subscriber --- src/interfacers/EmonHubMqttInterfacer.py | 117 +++++++++++++++++------ 1 file changed, 89 insertions(+), 28 deletions(-) diff --git a/src/interfacers/EmonHubMqttInterfacer.py b/src/interfacers/EmonHubMqttInterfacer.py index 014717fa..0b9aad34 100644 --- a/src/interfacers/EmonHubMqttInterfacer.py +++ b/src/interfacers/EmonHubMqttInterfacer.py @@ -52,7 +52,7 @@ def __init__(self, name, mqtt_user=" ", mqtt_passwd=" ", mqtt_host="127.0.0.1", # Add any MQTT specific settings self._mqtt_settings = { # emonhub/rx/10/values format - default emoncms nodes module - 'node_format_enable': 1, + 'node_format_enable': 0, 'node_format_basetopic': 'emonhub/', # nodes/emontx/power1 format @@ -74,6 +74,8 @@ def __init__(self, name, mqtt_user=" ", mqtt_passwd=" ", mqtt_host="127.0.0.1", self._connected = False + print("here") + self._mqttc = mqtt.Client() self._mqttc.on_connect = self.on_connect self._mqttc.on_disconnect = self.on_disconnect @@ -120,6 +122,17 @@ def add(self, cargo): # self.buffer.storeItem(f) + def read(self): + if not self._connected: + self._log.info("Connecting to MQTT Server") + try: + self._mqttc.username_pw_set(self.init_settings['mqtt_user'], self.init_settings['mqtt_passwd']) + self._mqttc.connect(self.init_settings['mqtt_host'], int(self.init_settings['mqtt_port']), 60) + except Exception: + self._log.info("Could not connect...") + time.sleep(1.0) # FIXME why sleep? we're just about to return True + + def _process_post(self, databuffer): if not self._connected: @@ -242,8 +255,17 @@ def on_connect(self, client, userdata, flags, rc): self._log.info("connection status: %s", connack_string[rc]) self._connected = True # Subscribe to MQTT topics - self._mqttc.subscribe(str(self._settings["node_format_basetopic"]) + "tx/#") - + if len(self._settings["pubchannels"]): + if int(self._settings["nodevar_format_enable"]) == 1: + self._log.info("subscribe "+str(self._settings["nodevar_format_basetopic"]) + "#") + self._mqttc.subscribe(str(self._settings["nodevar_format_basetopic"]) + "#") + if int(self._settings["node_format_enable"]) == 1: + self._log.info("subscribe "+str(self._settings["node_format_basetopic"]) + "#") + self._mqttc.subscribe(str(self._settings["node_format_basetopic"]) + "#") + if int(self._settings["node_JSON_enable"]) == 1: + self._log.info("subscribe "+str(self._settings["node_JSON_enable"]) + "#") + self._mqttc.subscribe(str(self._settings["node_JSON_basetopic"]) + "#") + self._log.debug("CONACK => Return code: %d", rc) def on_disconnect(self, client, userdata, rc): @@ -256,33 +278,72 @@ def on_subscribe(self, mqttc, obj, mid, granted_qos): def on_message(self, client, userdata, msg): topic_parts = msg.topic.split("/") - - if topic_parts[0] == self._settings["node_format_basetopic"][:-1]: - if topic_parts[1] == "tx": - if topic_parts[3] == "values": - nodeid = int(topic_parts[2]) - - payload = msg.payload,decode() - realdata = payload.split(",") - self._log.debug("Nodeid: "+str(nodeid)+" values: "+msg.payload) + self._log.debug("Received topic:"+str(msg.topic)) + self._log.debug("Received payload:"+str(msg.payload.decode())) + + rxc = False + + # General MQTT format: emon/emonpi/power1 ... 100 + if int(self._settings["nodevar_format_enable"]) == 1: + if topic_parts[0] == self._settings["nodevar_format_basetopic"][:-1]: + nodeid = topic_parts[1] + variable_name = "_".join(topic_parts[2:]) + try: + value = float(msg.payload.decode()) + realdata = [value] rxc = Cargo.new_cargo(realdata=realdata) - rxc.nodeid = nodeid - - if rxc: - # rxc = self._process_tx(rxc) - if rxc: - for channel in self._settings["pubchannels"]: - - # Initialize channel if needed - if not channel in self._pub_channels: - self._pub_channels[channel] = [] - - # Add cargo item to channel - self._pub_channels[channel].append(rxc) - - self._log.debug(str(rxc.uri) + " Sent to channel' : " + str(channel)) - + rxc.nodeid = nodeid + rxc.names = [variable_name] + + except Exception: + self._log.error("Payload format error") + + # Emoncms nodes module format: emon/tx/10/values ... 100,200,300 + if int(self._settings["node_format_enable"]) == 1: + if topic_parts[0] == self._settings["node_format_basetopic"][:-1]: + if len(topic_parts)==4 and topic_parts[1] == "tx" and topic_parts[3] == "values": + nodeid = topic_parts[2] + payload = msg.payload.decode() + realdata = payload.split(",") + try: + for i in range(0,len(realdata)): + realdata[i] = float(realdata[i]) + + rxc = Cargo.new_cargo(realdata=realdata) + rxc.nodeid = nodeid + except Exception: + self._log.error("Payload format error") + + # JSON format: zigbeemqtt/temp1 {"battery":100,"humidity":80,"temperature":22,"voltage":3100} + if int(self._settings["node_JSON_enable"]) == 1: + if topic_parts[0] == self._settings["node_JSON_basetopic"][:-1]: + nodeid = topic_parts[1] + json_string = msg.payload.decode() + try: + json_data = json.loads(json_string) + names = [] + values = [] + for key in json_data: + names.append(key) + values.append(json_data[key]) + rxc = Cargo.new_cargo(realdata=values) + rxc.nodeid = nodeid + rxc.names = names + except Exception: + self._log.error("Payload JSON format error") + if rxc: + for channel in self._settings["pubchannels"]: + + # Initialize channel if needed + if not channel in self._pub_channels: + self._pub_channels[channel] = [] + + # Add cargo item to channel + self._pub_channels[channel].append(rxc) + + self._log.debug(str(rxc.uri) + " Sent to channel' : " + str(channel)) + def set(self, **kwargs): super().set(**kwargs) From ab1e3c66e365c3c152fd3f3191ca25925d4516f8 Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Wed, 22 Mar 2023 14:53:37 +0000 Subject: [PATCH 2/8] mqtt pub examples for testing --- examples/mqtt_pub_json_format.py | 13 +++++++++++++ examples/mqtt_pub_node_format.py | 13 +++++++++++++ examples/mqtt_pub_nodevar_format.py | 13 +++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 examples/mqtt_pub_json_format.py create mode 100644 examples/mqtt_pub_node_format.py create mode 100644 examples/mqtt_pub_nodevar_format.py diff --git a/examples/mqtt_pub_json_format.py b/examples/mqtt_pub_json_format.py new file mode 100644 index 00000000..df0caecf --- /dev/null +++ b/examples/mqtt_pub_json_format.py @@ -0,0 +1,13 @@ +import time +import paho.mqtt.client as mqtt + +client = mqtt.Client() +client.username_pw_set("emonpi", "emonpimqtt2016") +client.connect("127.0.0.1", 1883, 60) + +while True: + topic = "zigbeemqtt/temp1" + payload = '{"battery":100,"humidity":80,"temperature":22,"voltage":3100}' + client.publish(topic, payload=payload, qos=0, retain=False) + # client.loop() + time.sleep(5.0) diff --git a/examples/mqtt_pub_node_format.py b/examples/mqtt_pub_node_format.py new file mode 100644 index 00000000..f1c537eb --- /dev/null +++ b/examples/mqtt_pub_node_format.py @@ -0,0 +1,13 @@ +import time +import paho.mqtt.client as mqtt + +client = mqtt.Client() +client.username_pw_set("emonpi", "emonpimqtt2016") +client.connect("127.0.0.1", 1883, 60) + +while True: + topic = "emonhub/tx/30/values" + payload = "1,1850" + client.publish(topic, payload=payload, qos=0, retain=False) + # client.loop() + time.sleep(5.0) diff --git a/examples/mqtt_pub_nodevar_format.py b/examples/mqtt_pub_nodevar_format.py new file mode 100644 index 00000000..17c017cb --- /dev/null +++ b/examples/mqtt_pub_nodevar_format.py @@ -0,0 +1,13 @@ +import time +import paho.mqtt.client as mqtt + +client = mqtt.Client() +client.username_pw_set("emonpi", "emonpimqtt2016") +client.connect("127.0.0.1", 1883, 60) + +while True: + topic = "zigbeemqtt/temp1/temperature" + payload = "18.5" + client.publish(topic, payload=payload, qos=0, retain=False) + # client.loop() + time.sleep(5.0) From 6a270ab49e58651b11eeb33930d869ee38456d44 Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Wed, 22 Mar 2023 14:56:35 +0000 Subject: [PATCH 3/8] remove here print --- src/interfacers/EmonHubMqttInterfacer.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/interfacers/EmonHubMqttInterfacer.py b/src/interfacers/EmonHubMqttInterfacer.py index 0b9aad34..f94676e9 100644 --- a/src/interfacers/EmonHubMqttInterfacer.py +++ b/src/interfacers/EmonHubMqttInterfacer.py @@ -74,8 +74,6 @@ def __init__(self, name, mqtt_user=" ", mqtt_passwd=" ", mqtt_host="127.0.0.1", self._connected = False - print("here") - self._mqttc = mqtt.Client() self._mqttc.on_connect = self.on_connect self._mqttc.on_disconnect = self.on_disconnect From 146901d0fd9815bab9222a0716af91cad9bf5a61 Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Wed, 22 Mar 2023 14:59:09 +0000 Subject: [PATCH 4/8] only subscribe to mqtt if not a subscribing interfacer --- src/interfacers/EmonHubMqttInterfacer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interfacers/EmonHubMqttInterfacer.py b/src/interfacers/EmonHubMqttInterfacer.py index f94676e9..e8f59628 100644 --- a/src/interfacers/EmonHubMqttInterfacer.py +++ b/src/interfacers/EmonHubMqttInterfacer.py @@ -253,7 +253,7 @@ def on_connect(self, client, userdata, flags, rc): self._log.info("connection status: %s", connack_string[rc]) self._connected = True # Subscribe to MQTT topics - if len(self._settings["pubchannels"]): + if len(self._settings["pubchannels"]) and !len(self._settings["subchannels"]): if int(self._settings["nodevar_format_enable"]) == 1: self._log.info("subscribe "+str(self._settings["nodevar_format_basetopic"]) + "#") self._mqttc.subscribe(str(self._settings["nodevar_format_basetopic"]) + "#") From 08066d00b451bb4c34b917df79b78812259847ae Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Wed, 22 Mar 2023 14:59:58 +0000 Subject: [PATCH 5/8] fix --- src/interfacers/EmonHubMqttInterfacer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interfacers/EmonHubMqttInterfacer.py b/src/interfacers/EmonHubMqttInterfacer.py index e8f59628..40810d40 100644 --- a/src/interfacers/EmonHubMqttInterfacer.py +++ b/src/interfacers/EmonHubMqttInterfacer.py @@ -253,7 +253,7 @@ def on_connect(self, client, userdata, flags, rc): self._log.info("connection status: %s", connack_string[rc]) self._connected = True # Subscribe to MQTT topics - if len(self._settings["pubchannels"]) and !len(self._settings["subchannels"]): + if len(self._settings["pubchannels"]) and not len(self._settings["subchannels"]): if int(self._settings["nodevar_format_enable"]) == 1: self._log.info("subscribe "+str(self._settings["nodevar_format_basetopic"]) + "#") self._mqttc.subscribe(str(self._settings["nodevar_format_basetopic"]) + "#") From e90b1af765969ed2ddcd81a89b2f5cad50a244d5 Mon Sep 17 00:00:00 2001 From: Trystan Lea Date: Fri, 24 Mar 2023 14:44:11 +0000 Subject: [PATCH 6/8] make it possible to more selective in topics to subscribe --- src/interfacers/EmonHubMqttInterfacer.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/interfacers/EmonHubMqttInterfacer.py b/src/interfacers/EmonHubMqttInterfacer.py index 40810d40..d17ce32a 100644 --- a/src/interfacers/EmonHubMqttInterfacer.py +++ b/src/interfacers/EmonHubMqttInterfacer.py @@ -255,14 +255,14 @@ def on_connect(self, client, userdata, flags, rc): # Subscribe to MQTT topics if len(self._settings["pubchannels"]) and not len(self._settings["subchannels"]): if int(self._settings["nodevar_format_enable"]) == 1: - self._log.info("subscribe "+str(self._settings["nodevar_format_basetopic"]) + "#") - self._mqttc.subscribe(str(self._settings["nodevar_format_basetopic"]) + "#") + self._log.info("subscribe "+str(self._settings["nodevar_format_basetopic"])) + self._mqttc.subscribe(str(self._settings["nodevar_format_basetopic"])) if int(self._settings["node_format_enable"]) == 1: - self._log.info("subscribe "+str(self._settings["node_format_basetopic"]) + "#") - self._mqttc.subscribe(str(self._settings["node_format_basetopic"]) + "#") + self._log.info("subscribe "+str(self._settings["node_format_basetopic"])) + self._mqttc.subscribe(str(self._settings["node_format_basetopic"])) if int(self._settings["node_JSON_enable"]) == 1: - self._log.info("subscribe "+str(self._settings["node_JSON_enable"]) + "#") - self._mqttc.subscribe(str(self._settings["node_JSON_basetopic"]) + "#") + self._log.info("subscribe "+str(self._settings["node_JSON_enable"])) + self._mqttc.subscribe(str(self._settings["node_JSON_basetopic"])) self._log.debug("CONACK => Return code: %d", rc) @@ -284,7 +284,7 @@ def on_message(self, client, userdata, msg): # General MQTT format: emon/emonpi/power1 ... 100 if int(self._settings["nodevar_format_enable"]) == 1: - if topic_parts[0] == self._settings["nodevar_format_basetopic"][:-1]: + # if topic_parts[0] == self._settings["nodevar_format_basetopic"][:-1]: nodeid = topic_parts[1] variable_name = "_".join(topic_parts[2:]) try: @@ -299,7 +299,7 @@ def on_message(self, client, userdata, msg): # Emoncms nodes module format: emon/tx/10/values ... 100,200,300 if int(self._settings["node_format_enable"]) == 1: - if topic_parts[0] == self._settings["node_format_basetopic"][:-1]: + # if topic_parts[0] == self._settings["node_format_basetopic"][:-1]: if len(topic_parts)==4 and topic_parts[1] == "tx" and topic_parts[3] == "values": nodeid = topic_parts[2] payload = msg.payload.decode() @@ -315,7 +315,7 @@ def on_message(self, client, userdata, msg): # JSON format: zigbeemqtt/temp1 {"battery":100,"humidity":80,"temperature":22,"voltage":3100} if int(self._settings["node_JSON_enable"]) == 1: - if topic_parts[0] == self._settings["node_JSON_basetopic"][:-1]: + # if topic_parts[0] == self._settings["node_JSON_basetopic"][:-1]: nodeid = topic_parts[1] json_string = msg.payload.decode() try: From 770bc7c6bf10cd339c5a5f87cd69f3887abe8322 Mon Sep 17 00:00:00 2001 From: Glyn Hudson Date: Wed, 3 May 2023 00:20:45 +0100 Subject: [PATCH 7/8] add docs for mqtt JSON subscribe --- docs/configuration.md | 183 +++++++++++++++++++++++++++++++++- docs/default-configuration.md | 151 +--------------------------- 2 files changed, 182 insertions(+), 152 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 0b67944b..78263212 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -95,6 +95,183 @@ The `Type` setting corresponds to the interfacer file name as found in `src/inte The remaining options are optional and if not specified will fall back to the interfacer defaults. +Example interfacers: + +### [[RFM2Pi]] + +The `[[RFM2Pi]]` interfacer section contains the settings to read from RFM69Pi / emonPi boards via GPIO internal serial port `/dev/ttyAMA0`. The default serial baud on all emonPi and RFM69Pi is `38400`. Older RFM12Pi boards using `9600` baud. + +The frequency and network group must match the hardware and other nodes on the network. + +The `calibration` config is used to set the calibration of the emonPi when using USA AC-AC adapters 110V. Set `calibration = 110V` when using USA AC-AC adapter. + +```text +[[RFM2Pi]] + Type = EmonHubJeeInterfacer + [[[init_settings]]] + com_port = /dev/ttyAMA0 + com_baud = 38400 # 9600 for old RFM12Pi + [[[runtimesettings]]] + pubchannels = ToEmonCMS, + subchannels = ToRFM12, + + group = 210 + frequency = 433 + baseid = 5 # emonPi / emonBase nodeID + quiet = true # Report incomplete RF packets (not implemented on emonPi) + calibration = 230V # (UK/EU: 230V, US: 110V) + # interval = 0 # Interval to transmit time to emonGLCD (seconds) +``` + +### [[MQTT]] + +#### MQTT Publishing + +Emonhub supports publishing to MQTT topics through the EmonHubMqttInterfacer. + +There are two formats that can be used for publishing node data to MQTT: + +#### **1. Node only format** + +(default base topic is `emonhub`) + +```text + topic: basetopic/rx/10/values + payload: 100,200,300 +``` + +The 'node only format' is used with the emoncms Nodes Module (now deprecated on Emoncms V9+) and the emonPiLCD python service. + +#### **2. Node variable format** + +(default base topic is `emon`) + +```text + topic: basetopic/emontx/power1 + payload: 100 +``` + +The 'Node variable format' is the current default format from Emoncms V9. It's a more generic MQTT publishing format that can more easily be used by applications such as NodeRED and OpenHab. This format can also be used with the emoncms `phpmqtt_input.php` script in conjunction with the emoncms inputs module. See [User Guide > Technical MQTT](https://guide.openenergymonitor.org/technical/mqtt/). + +#### **3. JSON format** + +##### Defaults + +```python +'node_format_enable': 1, +'node_format_basetopic': 'emonhub/', +'nodevar_format_enable': 0, +'nodevar_format_basetopic': "nodes/", +'node_JSON_enable': 0, +'node_JSON_basetopic': "emon/" +``` + +Emoncms default base topic that it listens for is `emon/`. + +```text +topic: basetopic/ +payload: {"key1":value1, "key2":value2, .... "time":, "rssi":} +``` + +This format exports the data as a single JSON string with key:value pairs. The timestamp is automatically added and used for the input time to emoncms. The RSSI is added if available (RF in use). + +### Default `[MQTT]` config + +Note - the trailing `/` is required on the topic definition. + +MQTT subscribe publish example: + +```text +[[MQTT]] + + Type = EmonHubMqttInterfacer + [[[init_settings]]] + mqtt_host = 127.0.0.1 + mqtt_port = 1883 + mqtt_user = emonpi + mqtt_passwd = emonpimqtt2016 + + [[[runtimesettings]]] + # pubchannels = ToRFM12, + subchannels = ToEmonCMS, + + # emonhub/rx/10/values format + # Use with emoncms Nodes module + node_format_enable = 0 + node_format_basetopic = emonhub/ + + # emon/emontx/power1 format - use with Emoncms MQTT input + # http://github.com/emoncms/emoncms/blob/master/docs/RaspberryPi/MQTT.md + nodevar_format_enable = 1 + nodevar_format_basetopic = emon/ + + # Single JSON payload published - use with Emoncms MQTT + node_JSON_enable = 0 + node_JSON_basetopic = emon/ +``` + +To enable one of the formats set the `enable` flag to `1`. More than one format can be used simultaneously. + +#### [[MQTT Subscribing]] + +EmonHub can subscribe to JSON MQTT topics, useful for integrating with [zigbee2mqtt](https://www.zigbee2mqtt.io/) and [Shelly WiFi sensors](https://community.openenergymonitor.org/t/shelly-plus-h-t-wireless-temperature-sensor-to-emoncms-via-mqtt/21991). + +MQTT subscribe example: + +```text +[[MQTT_sub]] + Type = EmonHubMqttInterfacer + [[[init_settings]]] + mqtt_host = 127.0.0.1 + mqtt_port = 1883 + mqtt_user = emonpi + mqtt_passwd = emonpimqtt2016 + [[[runtimesettings]]] + pubchannels = ToEmonCMS, + node_JSON_enable = 1 + node_JSON_basetopic = zigbee2mqtt/temp +``` +The above emonhub config subscribes to MQTT topic `zigbee2mqtt/temp` and decodes the JSON message `{"battery":100,"humidity":72.23,"linkquality":116,"temperature":21.79,"voltage":3000}` which results in an input key called `temp` and Inputs with battery, humidity etc. + +### [[emoncmsorg]] + +The EmonHubEmoncmsHTTPInterfacer configuration that is used for sending data to emoncms.org (or any instance of emoncms). If you wish to use emoncms.org the only change to make here is to replace the blank apikey with your write apikey from emoncms.org found on the user account page. See [Setup Guide > Setup > Remote logging](https://guide.openenergymonitor.org/setup/remote). + +```text + [[emoncmsorg]] + Type = EmonHubEmoncmsHTTPInterfacer + [[[init_settings]]] + [[[runtimesettings]]] + pubchannels = ToRFM12, + subchannels = ToEmonCMS, + url = https://emoncms.org + apikey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + senddata = 1 + sendstatus = 1 +``` + +`sendstatus` - It is possible to the EmonHubEmoncmsHTTPInterfacer to send a 'ping' to the destination emoncms that can be picked up by the myip module which will then list the source IP address. This can be useful for remote login to a home emonpi if port forwarding is enabled on your router. + +`senddata` - If you only want to send the ping request, and no data, to emoncms.org set this to 0 + +You can create more than one of these sections to send data to multiple emoncms instances. For example, if you wanted to send to an emoncms running at emoncms.example.com (or on a local LAN) you would add the following underneath the `emoncmsorg` section described above: + +```text + [[emoncmsexample]] + Type = EmonHubEmoncmsHTTPInterfacer + [[[init_settings]]] + [[[runtimesettings]]] + pubchannels = ToRFM12, + subchannels = ToEmonCMS, + url = https://emoncms.example.com + apikey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + senddata = 1 + sendstatus = 1 +``` + +This time, the API key will be the API key from your account at emoncms.example.com. + + --- ## 3. [Nodes] Configuration @@ -170,7 +347,7 @@ Indicates the host environment for human reference. **This field is optional.** [[[rx]]] ``` -This must be "rx" and specifies that the next section is for the config of the sensor values received from a node. Its also possible to define a "tx" section for variables to be sent to the node such as control state's. +This must be "rx" and specifies that the next section is for the config of the sensor values received from a node. It's also possible to define a "tx" section for variables to be sent to the node such as control state's. ### tx @@ -178,7 +355,7 @@ This must be "rx" and specifies that the next section is for the config of the s [[[tx]]] ``` -It's possible to transmitt data to other nodes via RFM e.g. the following config +It's possible to transmit data to other nodes via RFM e.g. the following config ```text [[[tx]]] @@ -191,7 +368,7 @@ The following data published to MQTT `emonhub/tx/20/values/14,38,34,700,138,2700,829` -Will result in the follwing data being transmitted via RF in JeeLib packet formatt: +Will result in the following data being transmitted via RF in JeeLib packet format: `14,38,34,700,138,2700,829` diff --git a/docs/default-configuration.md b/docs/default-configuration.md index 12dfff84..2c409ac2 100644 --- a/docs/default-configuration.md +++ b/docs/default-configuration.md @@ -13,154 +13,7 @@ The previous default emonhub configuration file installed on emonPi systems can The default interfacers employed are * RFM data decoding -* MQTT -* HTTP to emoncms.org +* MQTT Publish +* HTTPS to emoncms.org -### [[RFM2Pi]] -The `[[RFM2Pi]]` interfacer section contains the settings to read from RFM69Pi / emonPi boards via GPIO internal serial port `/dev/ttyAMA0`. The default serial baud on all emonPi and RFM69Pi is `38400`. Older RFM12Pi boards using `9600` baud. - -The frequency and network group must match the hardware and other nodes on the network. - -The `calibration` config is used to set the calibration of the emonPi when using USA AC-AC adapters 110V. Set `calibration = 110V` when using USA AC-AC adapter. - -```text -[[RFM2Pi]] - Type = EmonHubJeeInterfacer - [[[init_settings]]] - com_port = /dev/ttyAMA0 - com_baud = 38400 # 9600 for old RFM12Pi - [[[runtimesettings]]] - pubchannels = ToEmonCMS, - subchannels = ToRFM12, - - group = 210 - frequency = 433 - baseid = 5 # emonPi / emonBase nodeID - quiet = true # Report incomplete RF packets (not implemented on emonPi) - calibration = 230V # (UK/EU: 230V, US: 110V) - # interval = 0 # Interval to transmit time to emonGLCD (seconds) -``` - -### [[MQTT]] - -Emonhub supports publishing to MQTT topics through the EmonHubMqttInterfacer, defined in the interfacers section of emonhub.conf. - -There are two formats that can be used for publishing node data to MQTT: - -#### **1. Node only format** - -(default base topic is `emonhub`) - -```text - topic: basetopic/rx/10/values - payload: 100,200,300 -``` - -The 'node only format' is used with the emoncms Nodes Module (now deprecated on Emoncms V9+) and the emonPiLCD python service. - -#### **2. Node variable format** - -(default base topic is `emon`) - -```text - topic: basetopic/emontx/power1 - payload: 100 -``` - -The 'Node variable format' is the current default format from Emoncms V9. It's a more generic MQTT publishing format that can more easily be used by applications such as NodeRED and OpenHab. This format can also be used with the emoncms `phpmqtt_input.php` script in conjunction with the emoncms inputs module. See [User Guide > Technical MQTT](https://guide.openenergymonitor.org/technical/mqtt/). - -#### **3. JSON format** - -##### Defaults - -```python -'node_format_enable': 1, -'node_format_basetopic': 'emonhub/', -'nodevar_format_enable': 0, -'nodevar_format_basetopic': "nodes/", -'node_JSON_enable': 0, -'node_JSON_basetopic': "emon/" -``` - -Emoncms default base topic that it listens for is `emon/`. - -```text -topic: basetopic/ -payload: {"key1":value1, "key2":value2, .... "time":, "rssi":} -``` - -This forat exports the data as a single JSOn string with key:value pairs. The timestamp is automatically added and used for the input time to emoncms. The RSSI is added if available (RF in use). - -### Default `[MQTT]` config - -Note - the trailing `/` is required on the topic definition. - -```text -[[MQTT]] - - Type = EmonHubMqttInterfacer - [[[init_settings]]] - mqtt_host = 127.0.0.1 - mqtt_port = 1883 - mqtt_user = emonpi - mqtt_passwd = emonpimqtt2016 - - [[[runtimesettings]]] - # pubchannels = ToRFM12, - subchannels = ToEmonCMS, - - # emonhub/rx/10/values format - # Use with emoncms Nodes module - node_format_enable = 0 - node_format_basetopic = emonhub/ - - # emon/emontx/power1 format - use with Emoncms MQTT input - # http://github.com/emoncms/emoncms/blob/master/docs/RaspberryPi/MQTT.md - nodevar_format_enable = 1 - nodevar_format_basetopic = emon/ - - # Single JSON payload published - use with Emoncms MQTT - node_JSON_enable = 0 - node_JSON_basetopic = emon/ -``` - -To enable one of the formats set the `enable` flag to `1`. More than one format can be used simultaneously. - -### [[emoncmsorg]] - -The EmonHubEmoncmsHTTPInterfacer configuration that is used for sending data to emoncms.org (or any instance of emoncms). If you wish to use emoncms.org the only change to make here is to replace the blank apikey with your write apikey from emoncms.org found on the user account page. See [Setup Guide > Setup > Remote logging](https://guide.openenergymonitor.org/setup/remote). - -```text - [[emoncmsorg]] - Type = EmonHubEmoncmsHTTPInterfacer - [[[init_settings]]] - [[[runtimesettings]]] - pubchannels = ToRFM12, - subchannels = ToEmonCMS, - url = https://emoncms.org - apikey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - senddata = 1 - sendstatus = 1 -``` - -`sendstatus` - It is possible to the EmonHubEmoncmsHTTPInterfacer to send a 'ping' to the destination emoncms that can be picked up by the myip module which will then list the source IP address. This can be useful for remote login to a home emonpi if port forwarding is enabled on your router. - -`senddata` - If you only want to send the ping request, and no data, to emoncms.org set this to 0 - -You can create more than one of these sections to send data to multiple emoncms instances. For example, if you wanted to send to an emoncms running at emoncms.example.com (or on a local LAN) you would add the following underneath the `emoncmsorg` section described above: - -```text - [[emoncmsexample]] - Type = EmonHubEmoncmsHTTPInterfacer - [[[init_settings]]] - [[[runtimesettings]]] - pubchannels = ToRFM12, - subchannels = ToEmonCMS, - url = https://emoncms.example.com - apikey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - senddata = 1 - sendstatus = 1 -``` - -This time, the API key will be the API key from your account at emoncms.example.com. From 3ed6157e4bf1414b8d4c3a28852a00e7573ff6c5 Mon Sep 17 00:00:00 2001 From: GIT Admin Date: Sat, 27 Apr 2024 16:35:38 +0100 Subject: [PATCH 8/8] Fix broken rf transmit behaviour 1) The emonhub configuration for mqtt has both sub and pub - change the if statement at line 256 to allow this 2) Add tx/# to the mqtt subscribe at line 260 3) rf sendving via nodeval has 5 topic parts not 4, fix line 304 (see below) 4) Reinstate if statements: if topic_parts[0] == self._settings["nodevar_format_basetopic"][:-1]: and if topic_parts[0] == self._settings["node_format_basetopic"][:-1]: to avoid incorrect "Payload format error" messages To transmit via MQTT, example for emonglcd: topic:emonhub/tx/0/values/msg payload:10,14,49,25,27,04,24,150,835,1600,502 --- src/interfacers/EmonHubMqttInterfacer.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/interfacers/EmonHubMqttInterfacer.py b/src/interfacers/EmonHubMqttInterfacer.py index d17ce32a..b955089d 100644 --- a/src/interfacers/EmonHubMqttInterfacer.py +++ b/src/interfacers/EmonHubMqttInterfacer.py @@ -253,10 +253,12 @@ def on_connect(self, client, userdata, flags, rc): self._log.info("connection status: %s", connack_string[rc]) self._connected = True # Subscribe to MQTT topics - if len(self._settings["pubchannels"]) and not len(self._settings["subchannels"]): + if len(self._settings["pubchannels"]): if int(self._settings["nodevar_format_enable"]) == 1: self._log.info("subscribe "+str(self._settings["nodevar_format_basetopic"])) self._mqttc.subscribe(str(self._settings["nodevar_format_basetopic"])) + self._log.info("subscribe "+str(self._settings["nodevar_format_basetopic"]+ "tx/#")) + self._mqttc.subscribe(str(self._settings["node_format_basetopic"]) + "tx/#") if int(self._settings["node_format_enable"]) == 1: self._log.info("subscribe "+str(self._settings["node_format_basetopic"])) self._mqttc.subscribe(str(self._settings["node_format_basetopic"])) @@ -272,7 +274,7 @@ def on_disconnect(self, client, userdata, rc): self._connected = False def on_subscribe(self, mqttc, obj, mid, granted_qos): - self._log.info("on_subscribe") + self._log.debug("on_subscribe") def on_message(self, client, userdata, msg): topic_parts = msg.topic.split("/") @@ -284,7 +286,7 @@ def on_message(self, client, userdata, msg): # General MQTT format: emon/emonpi/power1 ... 100 if int(self._settings["nodevar_format_enable"]) == 1: - # if topic_parts[0] == self._settings["nodevar_format_basetopic"][:-1]: + if topic_parts[0] == self._settings["nodevar_format_basetopic"][:-1]: nodeid = topic_parts[1] variable_name = "_".join(topic_parts[2:]) try: @@ -299,8 +301,8 @@ def on_message(self, client, userdata, msg): # Emoncms nodes module format: emon/tx/10/values ... 100,200,300 if int(self._settings["node_format_enable"]) == 1: - # if topic_parts[0] == self._settings["node_format_basetopic"][:-1]: - if len(topic_parts)==4 and topic_parts[1] == "tx" and topic_parts[3] == "values": + if topic_parts[0] == self._settings["node_format_basetopic"][:-1]: + if len(topic_parts)==5 and topic_parts[1] == "tx" and topic_parts[3] == "values": nodeid = topic_parts[2] payload = msg.payload.decode() realdata = payload.split(",")