Friday, November 10, 2023

Domoticz with MicroPython part 3

For an index to all my stories click this text.

This is the third story in a series about sending data to, and receiving data from Domoticz with MicroPython.

The reason why I am writing these is because I migrated to a new internet provider. That meant reprogramming all of my microcontrollers. They needed to contact my new router and got new IP addresses. It was a hell of a job.

So I decided to reprogram the sensors in MicroPython. What made this easy is that all my favorite microcontrollers (ESP8266, ESP32 and Raspberry Pi Pico) are supported by MicroPython.

The first story describes connecting a pushbutton to a Raspberry Pi Pico and sending it's data to Domoticz. You can use this for a myriad of purposes like a doorcontact, a windowcontact, doorbell, PIR, vibration sensor, rain sensor etc. etc. Another purpose is using your Pico with a pushbutton as a remote control for your lamps. You can re-read that story here:
http://lucstechblog.blogspot.com/2023/11/domoticz-with-micropython-part-1.html

The second story describes how to build a switch in Domoticz that will set a led, attached to a microcontroller, on or off. You can re-read that story here:
http://lucstechblog.blogspot.com/2023/11/domoticz-with-micropython-part-2.html

In this story I am going to describe how we can send data from a microcontroller to Domoticz. The first story did the same but that was only an on or off signal. This time I am going to send values to Domoticz.

Again there are many purposes for this. Think temperature values from a digital thermometer, light intensity from an LDR, a fans rotation speed, measured distance from an ultrasonic sensor, water level from a tank etc.etc.

Breadboard setup

Actually it is the same setup from the first story. Just a Raspberry Pi pico with a pushbutton.



Nothing special here. The pushbutton is attached to GPIO14 and a 10K pull-up resistor is used. This is the same setup I used in the first story.

Please note that you can also use an ESP8266 or an ESP32 in stead of the Pico. Just alter the pin number where the button is attached to in the program.

What we are going to do.

For sending data from MicroPython to Domoticz we are gfoing to use the urequests library. This is the same library as we used in the first story and it is incorporated in the standard MicroPython distribution. So nothing to doenload.

As said you can use that for a myriad of sensors. For the sake of this example we are going to use a random value between 10 and 20. These values are used to simulate a thermometer.

The program will wait till you press a button and when you do a random value is send to Domoticz.
Domoticz will put this value in a simulated thermometer.

Creating a thermometer in Domoticz



In Domoticz coose the Setup tab and then the Hardware Entry. In the Name field fill in Virtual 1 and as type chose Dummy from the drop-down list. Then press the Add button.



A new entry will be made in your hardware list. It has the name Virtual 1 which you gave it.
Now click on Create Virtual Sensor.



I gave the virtual sensor the name MicroPython-test-thermometer and as type I chose Temperature from the drop down menu.

As you can see there are loads of options for sensors. I urge you to experiment a bit by choosing different sensors as Temperature later on. For now leave it as Temperature.

Press the OK button and Domotica will tell you that the sensor can be found in the devices tab. But don't bother.



The just created thermometer is immediately visible in the Temperature tab. As you can see I already had an outside thermometer. The MicroPython test thermometer says it is 0 degrees and that is because it has no data received yet.

To send data to this virtual thermometer we need to now it's ID (IDx) and that is easy to find.



Just press the edit button on your just created thermometer and there it is: Idx 23656
Your Idx number will definitely be different. Just note it down cause we are going to need this.

Domoticz API

To send data to Domoticz we can use it's API. You can find the API's documentation here:

https://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s

Now look for the section: 10 Update devices/sensors and especially at section 10.2 Temperature

/json.htm?type=command&param=udevice&idx=IDX&nvalue=0&svalue=TEMP

This is the command that Domoticz needs to set the thermometers value.
We just need to precede that by our Domoticz IP address. Alter the IDX in our just found Idx. And we need to replace TEMP by the temperature value.

The thermometers value says at this moment 0 degrees as the picture above shows.

To test if we did everything right, until now, paste the required API call into your browsers URL bar.



192.168.178.68:8080/json.htm?type=command&param=udevice&idx=23656&nvalue=0&svalue=18

This is my version.
My Domoticz has IP address 192.168.178.68:8080 in my network.
The thermometers ID is 23656
And I want to set the thermometer at 18 degrees.



And there you go. The browser send the data to Domoticz and the temperature was updated.

The only thing we have to do now, is to translate this API into a MicroPython program.

The MicroPython program.

This program actually is very similar to the program from the first story. We need Urequests to send data to Domoticz. And I added the random library (which is included with MicroPython) to generate a random number.

import random
import machine
import network
import urequests as requests
import gc
import time

button1 = machine.Pin(14, machine.Pin.IN)

ssid = "YOUR-ROUTERS-NAME"
pw = "PASSWORD"

wifi = network.WLAN(network.STA_IF)
wifi.active(True)
wifi.connect(ssid, pw)

print('Waiting for connection.',end="")
while wifi.isconnected() == False:
    time.sleep(1)
    print('', end='.')
print("")

ip = wifi.ifconfig()[0]

print("Connected with IP adress : "+ip)

while True:
    if button1.value() == 0:
        randval = random.randint(10,20)
        sendtemp = ("http://192.168.178.68:8080/json.htm?type=command&param=udevice&idx=23656&nvalue=0&svalue=")
        requests.get(sendtemp + str(randval))
        time.sleep(1)
        gc.collect()


This should pose no difficulties.

import random
import machine
import network
import urequests as requests
import gc
import time

button1 = machine.Pin(14, machine.Pin.IN)

The program starts with importing all necessary libraries and then defines GPIO14 as an input pin. This is the pin where the button is attached to.

ssid = "YOUR-ROUTERS-NAME"
pw = "PASSWORD"

wifi = network.WLAN(network.STA_IF)
wifi.active(True)
wifi.connect(ssid, pw)

print('Waiting for connection.',end="")
while wifi.isconnected() == False:
    time.sleep(1)
    print('', end='.')
print("")

ip = wifi.ifconfig()[0]

print("Connected with IP adress : "+ip)

This is the standard way to make a connection with your router. Do not forget to replace YOUR-ROUTERS-NAME and PASSWORD with your routers credentials.

The program tries to make a connection with the router and as long as that is not established a dot will be printed in Thonny's shell.
When te connection is made the microcontrollers IP address is printed in the shell.

while True:
    if button1.value() == 0:
        randval = random.randint(10,20)
        sendtemp = ("http://192.168.178.68:8080/json.htm?type=command&param=udevice&idx=23656&nvalue=0&svalue=")
        requests.get(sendtemp + str(randval))
        time.sleep(1)
        gc.collect()


This is where it all happens. The program waits till a button is pressed.  If that happens a random value between 10 and 20 is created and put in the randval variable. Next a string with the name sendtemp is created which has the main part of the API call. The only thing that is missing is the value we want to send.
That value is created in the next line where it is added to sendstring. Please notice that the random function creates an integer value which is made into a string with the str() command.
Make sure you replace the Idx value I used with your own value.

urequests clogs up some memory. And that memory needs to be freed again otherwise we might run into "out of memory" problems. That is where the Garbage collect library comes in. gc.collect() frees up any unused memory.

That is all.

Now repeatedly press the button attached to your Microcontroller and watch the value in Domoticz change.



Expansion

Nobody is keeping you from sending a value to multiple entries in Domoticz. For testing purposes I used the thermometer I created and created an extra sensor display with the type Custom Sensor.
That second sensor display got 23776 as it's Idx.

I just had to add 2 lines in the while loop:

while True:
    if button1.value() == 0:
        randval = random.randint(10,20)
        sendtemp = ("http://192.168.178.68:8080/json.htm?type=command&param=udevice&idx=23656&nvalue=0&svalue=")
        requests.get(sendtemp + str(randval))
        time.sleep(1)
        sendval = ("http://192.168.178.68:8080/json.htm?type=command&param=udevice&idx=23776&nvalue=0&svalue=")
        requests.get(sendval + str(randval))
        time.sleep(1)
        gc.collect()


And I had two sensor displays. The thermometer was in the Temperature tab and the custom sensor in the Utility tab.



Of course they got the same value because I only generated 1 random value and send that same value twice to Domoticz.

This is only an illustration to show that you can attach multiple sensors to the same microcontroller and send all values to domoticz.

Just experiment with this and I am sure you can come up with some clever solutions for your home automation.

MicroPython ???

For those that have no experience with MicroPyton and want to learn the languages and how to use it with a Raspberry Pi Pico I can recommend two books I wrote on this subject and which you can find a link for at the bottom of this story.

And do have a look at my new website that is tjokfull with tips for programming in MicroPython:
https://micropython-tips.weebly.com/


Till next time
Have fun


Luc Volders