Example project: PIR sensor and Domoticz API
-
I've done a small project on my WiPy 1.0 with a PIR sensor to turn on a lamp in my home using my existing Domoticz setup. I'm using this sensor. This project can be found on this repo. Below a small report of the project and the code.
The setup
For every motion trigger, a message is sent to the domoticz api to update a 'user variable'. The domoticz installation, which is running on a RasPi, has a lua script that triggers when this variable changes and turns one lamp on for 2 minutes. (It uses the rfxcom 433 tranceiver and cheap pieces of hardware in my lamps, but that's not relevant now) My kitchen seemed like a good place to implement this, since the lights there only need to be on when there is motion.To make it run from the 3.3v out of the WiPy, I soldered a wire to bypass the 5v to 3.3v stepdown on the back of the PIR board. When the sensor triggers, it pulls the pin up for about 5 or 6 seconds, after which it drops back, ready for more triggers. This means I don't have to build in any mechanism to prevent sending http requests too often, which is nice.
Main.py
I kept everything very simple, so it's easy for others to grab and adept for their own purposes. Besides the sensor, I also listen to a button press on the expansion board to break the main loop, which I found useful for testing. To make it work with your domoticz, just replace <ip> and <basic hash> with your values.import time from network import WLAN from machine import Pin from domoticz import Domoticz wl = WLAN(WLAN.STA) d = Domoticz("<ip>", 8080 ,"<basic hash>") #flags running = True button_pressed = False pir_triggered = False #callbacks def pirTriggered(pin): global pir_triggered pir_triggered = True def buttonPressed(pin): global button_pressed button_pressed = True pir = Pin('GP4',mode=Pin.IN,pull=Pin.PULL_UP) pir.irq(trigger=Pin.IRQ_RISING, handler=pirTriggered) pir = Pin('GP17',mode=Pin.IN,pull=Pin.PULL_UP) pir.irq(trigger=Pin.IRQ_FALLING, handler=buttonPressed) # main loop print("Starting main loop") while running: time.sleep_ms(500) if pir_triggered: pir_triggered = False result = d.setVariable('Presence:LivingRoom','1') print("HTTP Status: "+str(result)) elif button_pressed: button_pressed = False running = False print("Exited main loop")
Domoticz class
This implements a simple http get request and 2 domoticz api endpoints. Implementation consists of setting values of devices and user-variables.I tried implementing the micropython-http-client class from balloob (I simply copied the class into my project), but I found that after 4 successful http requests it stopped working for some reason. So for now, I'm just using the bare sockets in the simplest way possible.
import socket class Domoticz: def __init__(self, ip, port, basic): self.basic = basic self.ip = ip self.port = port def setDevice(self, idx, command): print("Setting device "+idx+" to "+command) return self.sendRequest("type=command¶m=switchlight&idx="+idx+"&switchcmd="+command) def setVariable(self, name, value): print("Setting variable "+name+" to "+value) return self.sendRequest("type=command¶m=updateuservariable&vtype=0&vname="+name+"&vvalue="+value) def sendRequest(self, path): try: s = socket.socket() s.connect((self.ip,self.port)) s.send(b"GET /json.htm?"+path+" HTTP/1.1\r\nHost: pycom.io\r\nAuthorization: Basic "+self.basic+"\r\n\r\n") status = str(s.readline(), 'utf8') code = status.split(" ")[1] s.close() return code except Exception: print("HTTP request failed") return 0
Boot.py
I slightly adapted the wifi code to support fixed IP on different wifi networksimport os import machine uart = machine.UART(0, 115200) os.dupterm(uart) known_nets = { '<net>': {'pwd': '<password>'}, '<net>': {'pwd': '<password>', 'wlan_config': ('10.0.0.114', '255.255.0.0', '10.0.0.1', '10.0.0.1')}, # (ip, subnet_mask, gateway, DNS_server) } if machine.reset_cause() != machine.SOFT_RESET: from network import WLAN wl = WLAN() wl.mode(WLAN.STA) original_ssid = wl.ssid() original_auth = wl.auth() print("Scanning for known wifi nets") available_nets = wl.scan() nets = frozenset([e.ssid for e in available_nets]) known_nets_names = frozenset([key for key in known_nets]) net_to_use = list(nets & known_nets_names) try: net_to_use = net_to_use[0] net_properties = known_nets[net_to_use] pwd = net_properties['pwd'] sec = [e.sec for e in available_nets if e.ssid == net_to_use][0] if 'wlan_config' in net_properties: wl.ifconfig(config=net_properties['wlan_config']) wl.connect(net_to_use, (sec, pwd), timeout=10000) while not wl.isconnected(): machine.idle() # save power while waiting print("Connected to "+net_to_use+" with IP address:" + wl.ifconfig()[0]) except Exception as e: print("Failed to connect to any known network") wl.init(mode=WLAN.AP, ssid=original_ssid, auth=original_auth, channel=6, antenna=WLAN.INT_ANT)
Plans:
- Making the http library from Balloob wor properly, or implementing a new http wrapper class
- Add more sensors like temperature and lux to this same project and send these values to domoticz
- Expand domoticz class to support the full api
EDIT
The API on the esp32 devices for Pin has changed. The pir.irq method has been replaced by pin.callback. The correct implementation for these devices would be:pir = Pin('G4',mode=Pin.IN,pull=Pin.PULL_UP) pir.callback(trigger=Pin.IRQ_RISING, handler=pirTriggered) pir = Pin('G17',mode=Pin.IN,pull=Pin.PULL_UP) pir.callback(trigger=Pin.IRQ_FALLING, handler=buttonPressed)
-
Can someone help me out on how to setup a domoticz for this project? And also the changes that are required to be made to the code.
-
@Ralph OK great. Not sure if you took this project any further (?) but I am working on something almost identical. https://forum.pycom.io/topic/1308/wipy-motion-and-ambient-conditions-sensor-node
Cheers
-
@robmarkcole Correct, thanks for pointing this out. I added a note to this post now with the correct code.
-
@Ralph Does this need to be updated since callbacks are not handled with pin.irq (deprecated?) but pin.callback? https://docs.pycom.io/pycom_esp32/library/machine.Pin.html#machine.Pin
-
@Xykon You are right, I might as well have left it on the 5V.
I'm running it without the expansion board and only soldered one connector to the 5v out of an old usb cable that I stripped. I could have added another connector on hindsight, but at that point it seemed easier to use the free 3.3v out pin on the wipy and bypass the stepdown.
-
Thanks a lot for sharing the project
I soldered a wire to bypass the 5v to 3.3v stepdown on the back of the PIR board
I'm curious why you did that instead of powering the PIR sensor from 5V through VIN? The only reason I could think of is that you are using a 3.7V LIPO to power the Wipy2. But if it's installed in an area where you have power anyway I'm wondering why you would rely on a battery powered solution.