I tried to write my own Python script to test this out. It might be interesting to others and I have some questions at the end. That’s the reason for this step-by-step post.
- Introduction
- Paho-mqtt
- Publish 2 values once
- Publish 2 values in a loop
- Script to background
- Remaining questions
Introduction
I suppose you already have a running emoncms and you have a meter/sensor/… where the values should become available in emoncms. Your steps are:
- Check if it works out-of-the-box in emoncms.
- If not, check if an interfacer for that meter/sensor/… exists and configure it in emonhub.
- If not, post Data to Emoncms yourself. The link explains that you can use ‘Emoncms HTTP Input API‘ or ‘MQTT’. I’ll use the MQTT solution for my situation, but unfortunately the link is very short in explanation. So I tried to write my own Python script to test out.
My situation: I have three daisy chained modbus kWh meters to monitor my household (SDM630), heat pump (SDM120) and solar panels (SDM120). My hardware setup is explained in this topic. An emonhub interfacer exists for one modbus meter per cable/RS485-USB, but not for daisy chained meters yet (see this topic). So I’m looking to write a Python script to publish the data to the MQTT broker of OpenEnergyMonitor. Before diving into details, I explain some core concepts, the way I see them.
- Emoncms is an open-source web application or processing, logging and visualising energy, temperature and other environmental data. To be able to process data in emoncms it should first be registered as an input.
- EmonHub is a piece of software that can read/subscribe or send/publish data to and from a multitude of services. Eg. a SDS011 air-quality sensor that produces values about PM2.5 and PM10 and where an emonhub interfacer exist to have those values as inputs in emoncms. So some interfacers already exist, but what if you have a situation where such interfacer doesn’t exist yet?
- Well, MQTT is used as a way to pass data in the OpenEnergyMonitor (OEM) ecosystem. This ‘Message Queuing Telemetry Transport’ allows you to publish data (sensors, meters, …) to a central server. This central server is called a broker and the software OEM uses is Mosquitto. Every topic that is published automatically appears as an input in emoncms, as emoncms subscribes to these emon-topics. I found ‘MQTT Essensials’ on hivemq.com very interesting to learn more about MQTT.
I will just publish a counter and some random value to inputs at emoncms, to be able to focus on the essentials. The end goal on the input page is:
Mind you: I’m no specialist in neither emoncms, MQTT or Python. So chances are big that I could have done things better. Please let me know.
Paho-mqtt
My inspiration comes from this script of Steve Cope and uses paho-mqtt as Python client library. To install:
~$ pip install paho-mqtt
Publish 2 values once
The basic steps are:
- The settings: server ip, username, password, …
- Connecting to the MQTT server broker (localhost, IP, domain name, …)
- Publish values to emoncms. The topic must start with
emon
, but the other parts are free to choose. In my case I useemon/mynode/counter
andemon/mynode/random
which will create 1 nodemynode
in emoncms with the 2 inputscounter
andrandom
. The value of this input will be 1 forcounter
and a random number forrandom
.
The script python2emoncms.py
:
import paho.mqtt.client as mqtt
import random
import time
# Settings
CLEAN_SESSION=True #See https://www.hivemq.com/mqtt-essentials/ > part 7
broker="localhost"
username="emonpi" #See [mqtt]-section of /var/www/emoncms/settings.ini
password="emonpimqtt2016"
# Functions, further on assigned to correct callback of paho (see client1.on_... = ...)
def on_disconnect(client, userdata, flags, rc=0):
m="def-DisConnected flags "+"result code "+str(rc)
print(m)
def on_connect(client, userdata, flags, rc):
print("def-Connected flags ",str(flags),"result code ",str(rc))
def on_message(client, userdata, message):
print("def-Message received " ,str(message.payload.decode("utf-8")))
def on_publish(client, userdata, mid):
print("def-Message published ", str(mid))
# Creating paho-instance and connect
print("Creating client 1 with clean session set to", CLEAN_SESSION)
client1 = mqtt.Client("Python1",clean_session=CLEAN_SESSION) #create new instance
client1.username_pw_set(username,password)
client1.on_message=on_message
client1.on_connect=on_connect
print("Connecting to MQTT broker",broker)
client1.on_publish = on_publish
client1.connect(broker)
client1.loop_start()
# Publish values to emoncms
value1 = 1
value2=random.randint(0, 10000)/1000
print(value1, " ; " , value2)
ret=client1.publish("emon/mynode/counter",value1)
ret=client1.publish("emon/mynode/random",value2)
# Disconnect
client1.on_disconnect=on_disconnect
time.sleep(3)
#client1.loop()
client1.disconnect()
client1.loop_stop()
The output:
~$ python3 python2emoncms.py
Creating client 1 with clean session set to True
Connecting to MQTT broker localhost
1 ; 2.158
def-Connected flags {'session present': 0} result code 0
def-Message published 1
def-Message published 2
def-DisConnected flags result code 0
Open emoncms > Input and you should see 1 node mynode
and the 2 inputs counter
and random
automatically created, displaying their corresponding values. The input page doesn’t always show all the digits (eg. 2.16) as they are stored (eg. 2.158), but they can be made visible on the dashboard (see this topic). You can reexecute the script: the first value will always be 1, the second value is a random value.
Publish 2 values in a loop
When thinking about sensors or meters you’ll want a loop to take a new value every x seconds. I adapted the script (using this as inspiration) to execute the ‘Publish values to emoncms’ part every 10 seconds:
# Publish values to emoncms
value1 = 0
while True:
value1 = value1 + 1
value2=random.randint(0, 10000)/1000
print(value1, " ; " , value2)
ret=client1.publish("emon/mynode/counter",value1)
ret=client1.publish("emon/mynode/random",value2)
time.sleep(10)
The output (as there is an infinite loop, you’ll have to stop the script with ctrl + c):
~$ python3 python2emoncms.py
Creating client 1 with clean session set to True
Connecting to MQTT broker localhost
1 ; 2.051
def-Connected flags {'session present': 0} result code 0
def-Message published 1
def-Message published 2
2 ; 7.439
def-Message published 3
def-Message published 4
3 ; 4.935
def-Message published 5
def-Message published 6
The complete script becomes (where I have disable the on_publish callback
to have a more condens output):
import paho.mqtt.client as mqtt
import random
import time
# Settings
CLEAN_SESSION=True #See https://www.hivemq.com/mqtt-essentials/ > part 7
broker="localhost"
username="emonpi" #See [mqtt]-section of /var/www/emoncms/settings.ini
password="emonpimqtt2016"
# Functions, further on assigned to correct callback of paho (see client1.on_... = ...)
def on_disconnect(client, userdata, flags, rc=0):
m="def-DisConnected flags "+"result code "+str(rc)
print(m)
def on_connect(client, userdata, flags, rc):
print("def-Connected flags ",str(flags),"result code ",str(rc))
def on_message(client, userdata, message):
print("def-Message received " ,str(message.payload.decode("utf-8")))
def on_publish(client, userdata, mid):
print("def-Message published ", str(mid))
# Creating paho-instance and connect
print("Creating client 1 with clean session set to", CLEAN_SESSION)
client1 = mqtt.Client("Python1",clean_session=CLEAN_SESSION) #create new instance
client1.username_pw_set(username,password)
client1.on_message=on_message
client1.on_connect=on_connect
print("Connecting to MQTT broker",broker)
#client1.on_publish = on_publish
client1.connect(broker)
client1.loop_start()
# Publish values to emoncms
value1 = 0
while True:
value1 = value1 + 1
value2=random.randint(0, 10000)/1000
print(value1, " ; " , value2)
ret=client1.publish("emon/mynode/counter",value1)
ret=client1.publish("emon/mynode/random",value2)
time.sleep(10)
# Disconnect
client1.on_disconnect=on_disconnect
time.sleep(3)
#client1.loop()
client1.disconnect()
Script to background
One problem remains: if I close my terminal, the script also stops executing. Luckily I found this topic, so:
~$ nohup python3 python2emoncms.py &
To stop the script for one reason or another:
~$ ps ax | grep python2emoncms.py
696690 pts/0 Sl 0:00 python3 python2emoncms.py
696696 pts/0 S+ 0:00 grep --color=auto python2emoncms.py
~$ kill -9 696690
Remaining questions
Some questions remain… and I don’t know the answers :
-
CLEAN_SESSION
is true or should it be set to false? - What about the QOS levels in MQTT?
- I’m not sure if the paho-functions
loopstart
,loop
andloop_stop
are necassary and their documentation doesn’t make me any wiser. - Is it a problem that the script will never reach the
client1.disconnect
? The script will only stop on crash/reboot/kill. - If my server reboots, it doesn’t automatically restart the script. Also, if the script crashes, it will not restart. This Linux service could be an inspiration (but I think it should only start after network and mosquitto is up and running), but manually starting the script is okay for me at the moment.
Of course, the script doesn’t do anything valuable: it should be extended to be able to read sensors, meters, … But I didn’t want to make it too complex and focus on "how can you use Python to publish values to emoncms with MQTT’. If you have any remarks to make it better: shoot .