Page 1 of 1
UniPi plugin - question
Posted: Tuesday 07 February 2017 13:21
by ubee
I have developed a Python plugin for UniPi module. Right now it supports relay control (8 builit in relays) by 8 Domoticz switches, and also readout of 1-wire temp sensors connected to the UniPi. The temp sensors are automatically detected and added to Domoticz, and any additional temp sensors added later will also be automatically detected and added to Domoticz. The plugin works fine with the latest beta (3.6584).
I use the EVOK software provided by UniPi Technology to access the module and attached sensors. In my plugin I use the EVOK REST interface addressing localhost, by using urlopen and data is decoded by json.loads. I don't use the built in TCP support in the plugin system, since I don't see any real benefit of doing so. The UniPi module is connected to the Rasp I2C bus, so I believe the response will be more or less immediate. By that I doubt I will gain anything by the asynchronous interface provided by the plugin system. Synchronous calls works fine as far as I can see.
Do you agree with my conclusion that synchronous calls is fine for on-board resources, even if they are accessed with a network protocol?
Re: UniPi plugin - question
Posted: Wednesday 08 February 2017 21:05
by Dnpwwo
@ubee,
If your plugin works by polling the external hardware only then there may be little benefit. If the hardware can send messages to the plugin then there would be a significant benefit because your plugin would be much more responsive.
Connecting over TCP can result in a wait of up to 30 seconds if the network name isn't found (which the built in connectivity will handle for you) but localhost probably won't have that problem.
Re: UniPi plugin - question
Posted: Thursday 09 February 2017 12:54
by ubee
@Dnpwwo,
Thanks for confirming my assumptions are OK. I'm just polling or pushing commands. No unsolicited messages from the HW device, so I will keep the design as it is. The plugin works fine. A big improvement compared to a solution based on virtual switches and a LUA script that I tried to begin with.
Re: UniPi plugin - question
Posted: Monday 13 February 2017 23:20
by jcmschoot
Is there any possibility to use asynchronos (websocket) calls? If i read correctly the Python plugin framework doesn't support the async structure..
Re: UniPi plugin - question
Posted: Tuesday 14 February 2017 13:54
by Dnpwwo
@jcmschoot,
The framework does support async calls.
Plugins that set the transport and connect via the framework will be called via the onMessage calll back whenever messages arrive. If you look at the /plugins/examples folder the RAVEn, Kodi and Denon4306 plugins all recieve async messages. Some as a response to commands sent to them but also completely async messages from events on the devices themselves.
I haven't tested websockets explicitly but there is no reason they wouldn't work. The Dlink DSP-W215 example shows how to connect to HTTP:
Code: Select all
Domoticz.Transport(Transport="TCP/IP", Address=Parameters["Address"], Port=Parameters["Port"])
Domoticz.Protocol("HTTP")
Domoticz.Connect()
once connected the onConnect is called you specify the message and headers
Code: Select all
headers = { 'Content-Type': 'text/xml; charset=utf-8', \
'Connection': 'keep-alive', \
'Accept': 'Content-Type: text/html; charset=UTF-8', \
'Host': Parameters["Address"]+":"+Parameters["Port"], \
'User-Agent':'Domoticz/1.0', \
'Upgrade': 'websocket', \
'Connection':' Upgrade', \
'Content-Length' : "%d"%(len(data)) }
Domoticz.Send(data, 'POST', 'index.html', headers)
the data supplied to onMessage is utf-8 so binary data should come through intact.
Re: UniPi plugin - question
Posted: Saturday 04 March 2017 14:48
by swevm
Interesting.
I´m just about to buy a UniPi Neuron to replace my central Domoticz with something more professional. Are you willing to share your plugin and let other work collaboratively to enhance it?
/Magnus
ubee wrote:@Dnpwwo,
Thanks for confirming my assumptions are OK. I'm just polling or pushing commands. No unsolicited messages from the HW device, so I will keep the design as it is. The plugin works fine. A big improvement compared to a solution based on virtual switches and a LUA script that I tried to begin with.
Re: UniPi plugin - question
Posted: Saturday 04 March 2017 15:20
by ubee
Sure, here it comes. I think you find what you need in the description in the file header. So far, I have just implemented support for the relays and 1 wire temp sensors. I hope someone will create a GIT repository (or similar) for plugins.
Code: Select all
# UniPI plugin
#
# Author: Ubee
#
# This file will provide native support for UniPi in Domoticz. Right now the python plugin support is only supported by the beta version of Domoticz. Install the latest stable release, and
# then you can easily upgrade to latest beta by running the updatebeta script in the domoticz folder. The plugin system also requires python3 on your Rasp.
#
# You also need to install the EVOK software before adding this module. Make sure EVOK runs OK. You can check with EVOK built in web interface. Note: there is a problem with the EVOK install
# script on Raspbian Jessie. EVOK daemon must be started with a /etc/init.d script. The install script tries to use the systemctl command, but this does not work.
#
# Once the above mentioned prerequisites are in place, you are ready to install this module. Put this file, plugin.py, in the following folder and restart the Rasp:
#
# domoticz/plugins/UniPIx
#
# Note 0: The file must be named plugin.py and stored in the above mentioned directory. And the directory must be named UniPIx. Beware of the naming. It is case sensitive, and no other file must
# be stored in the UniPIx directory.
#
# Then you are ready to add a UniPi module on the Setup page and the HW tab. Choose "UniPI" in the drop-down list, specify a name of the unit, and the port number used for EVOK. This number must match
# the one specified in the evok.conf file. You may also choose "Debug" mode, which will give a few more printouts in the domoticz log file if you have specified such one. Then click "Add". As soon as
# you have done this, 8 switches controlling the relays have been added to Domoticz. Temperature devices will show up with a few minutes after the have been connected. The temperatures are read every
# 60s, and every 3rd minute the system looks for new sensors. If a sensor is lost or disconnected, they will still be visible in Domoticz. You will notice they have disappeared by latest update time.
#
# NOTE 1: Don't delete temp devices that are not longer connected to the system. This will lead to a program crash! If you want to get rid of unused (unavailable) temp sensors, you can disable
# the corresponding device on the Device tab on the Setup page. If you reboot the system, all unavailable temp sensors will disappear.
#
# NOTE 2: Currently the Domoticz plugin system have a problem with the Chrome browser. Occasionally, it is not possible to add new HW units supported by plugin modules. You recognize this problem
# by finding the name of the HW type at the end of the drop-down list you use to select the HW type you want to add. If you choose that option anyway, you cannot specify any HW parameters and you will
# just load an "empty" module that doesn't work. This problems seems to be correlated with the Chrome browser. Firefox, IE and Edge work fine.
#
#
#
#
"""
<plugin key="UniPIx" name="UniPI" author="ubee" version="1.0.0" wikilink="http://www.domoticz.com/wiki/plugins/plugin.html" externallink="https://www.google.com/">
<params>
<param field="Port" label="Port" width="30px" required="true" default="8082"/>
<param field="Mode1" label="Debug" width="75px">
<options>
<option label="True" value="Debug"/>
<option label="False" value="Normal" default="true" />
</options>
</param>
</params>
</plugin>
"""
import Domoticz,json
from urllib.request import urlopen
from urllib.parse import urlencode
heartbeatCount=0
HEARTBEAT_DIV=3 # Every n:th call will trigger temp sensor detection
OneWireIds=list() # list of detected 1-wire sensors. First element in list maps to Unit[24] in Domoticz.Device array
UNIPI_URL="localhost:"
def onStart():
#
# Create all static devices available on UniPi, i.e. 8 relay devices, 12 digital inputs, 2 analog input ports and 1 analog output port.
#
# Relays are defined as Domoticz Switches - Unit 1..8
# Ditital Inputs as Domoticz Switch Contact - Unit 9..20 - Not Implemented
# Analog Inputs as Domoticz Voltage - Unit 21,22 - Not implemented
# Analog Output as Domoticz Voltage - Unit 23 - Not implemented
#
# 1-wire temp sensors are created dynamically when they are connected. They are detected in the onHeartbeat callback function
# Temp sensors - Unit 24..
#
global UNIPI_URL
Domoticz.Log("onStart called")
UNIPI_URL=UNIPI_URL+Parameters["Port"]
if Parameters["Mode1"] == "Debug":
Domoticz.Debugging(1)
if (len(Devices) == 0):
for n in range(1,9):
Domoticz.Device(Name="Relay "+str(n), Unit=n, TypeName="Switch").Create()
Domoticz.Log("Relay Devices created.")
#
# pick up all previolusly detected 1-wire sensors
#
if len(Devices)>8:
response = urlopen("http://"+ UNIPI_URL+"/rest/all").read().decode('utf-8')
data=json.loads(response)
for item in data:
if item["dev"] == "temp":
OneWireIds.append(item["circuit"])
DumpConfigToLog()
Domoticz.Heartbeat(60)
return True
def onStop():
Domoticz.Log("onStop called")
return True
def onConnect(Status, Description):
Domoticz.Log("onConnect called")
return True
def onMessage(Data, Status, Extra):
Domoticz.Log("onMessage called")
return True
def onCommand(Unit, Command, Level, Hue):
Domoticz.Log("onCommand called for Unit " + str(Unit) + ": Parameter '" + str(Command) + "', Level: " + str(Level))
Command = Command.strip()
# action, sep, params = Command.partition(' ')
# action = action.capitalize()
#
# 8 first units are relays that can be toggled
#
if Unit in range(1,9):
if (Command == 'On'):
RelaySet(Unit,1)
UpdateDevice(Unit,1,'On')
elif (Command == 'Off'):
RelaySet(Unit,0)
UpdateDevice(Unit,0,'Off')
return True
def onNotification(Data):
Domoticz.Log("onNotification: " + str(Data))
return True
def onDisconnect():
Domoticz.Log("onDisconnect called")
return True
def onHeartbeat():
#
# Called periodically
#
# Every n:th call, the 1-wire bus will be scanned for new temp sensors and added
#
# For every call read all temp sensors and update accordingly
#
# Read digital inputs - not implemented yet
# Read analog inputs - not implemented yet
#
global heartbeatCount
global OneWireIds
Domoticz.Log("onHeartbeat called")
response = urlopen("http://"+ UNIPI_URL+"/rest/all").read().decode('utf-8')
data=json.loads(response)
if heartbeatCount == 0:
Domoticz.Log("Scan for new temp sensors")
#
# For each found temp sensor, check if Domoticz device is defined for this sensor. If not, create the device.
#
for item in data:
if item["dev"] == "temp":
checkAppend(item["circuit"])
#
# Check all defined Domoticz temp devices. If any of those is not available, delete device the device if last update of the device is more than one hour ago.
# - Not implemented. Maybe is not an good idea to do this? Better to manually delete removed sensors.
#
# ----- End of update of sensors
#
# Update Domoticz temp devices with current reading on every hearbeat
#
if len(OneWireIds) > 0:
for n in range(0,len(OneWireIds)):
if findSensor(OneWireIds[n],data):
Domoticz.Debug("Update temp from 1-wire sensor #"+ str(n+1) +" "+ OneWireIds[n])
Devices[24+n].Update(nValue=int(findSensor(OneWireIds[n],data)),sValue=str(findSensor(OneWireIds[n],data)))
heartbeatCount=heartbeatCount+1
if heartbeatCount==HEARTBEAT_DIV:
heartbeatCount=0
return True
# Generic helper functions
def DumpConfigToLog():
for x in Parameters:
if Parameters[x] != "":
Domoticz.Debug( "'" + x + "':'" + str(Parameters[x]) + "'")
Domoticz.Debug("Device count: " + str(len(Devices)))
for x in Devices:
Domoticz.Debug("Device: " + str(x) + " - " + str(Devices[x]))
Domoticz.Debug("Device ID: '" + str(Devices[x].ID) + "'")
Domoticz.Debug("Device Name: '" + Devices[x].Name + "'")
Domoticz.Debug("Device nValue: " + str(Devices[x].nValue))
Domoticz.Debug("Device sValue: '" + Devices[x].sValue + "'")
Domoticz.Debug("Device LastLevel: " + str(Devices[x].LastLevel))
for item in OneWireIds:
Domoticz.Debug("1-wire sensor "+ item)
return
def UpdateDevice(Unit, nValue, sValue):
# Make sure that the Domoticz device still exists (they can be deleted) before updating it
Domoticz.Debug("Update unit no: "+str(Unit)+" value: "+ str(nValue)+" "+ str(sValue))
if (Unit in Devices):
if (Devices[Unit].nValue != nValue) or (Devices[Unit].sValue != sValue):
Devices[Unit].Update(nValue, str(sValue))
Domoticz.Log("Update "+str(nValue)+":'"+str(sValue)+"' ("+Devices[Unit].Name+")")
return
#
# Control the relay indexed by Unit.
# nValue = 0 Relay off
# nValue = 1 Relay on
#
def RelaySet(Unit,nValue):
Domoticz.Debug("Relay no: "+str(Unit)+" value: "+ str(nValue))
response = urlopen("http://"+ UNIPI_URL+"/rest/relay/"+str(Unit),bytes(urlencode({'value': str(nValue)}),'utf-8')).read()
return
def findSensor(strId,data):
for item in data:
if item["dev"] == "temp":
if item["circuit"]==strId and not item["lost"]:
return item["value"]
return False
def checkAppend(sensorId):
#
# Scan through all temp devices (index 24 and upward, number of devices given by len(OneWireIds).
# If sensor is not found, create a new temp device. Store sensorId in options field
#
global OneWireIds
for n in range(0,len(OneWireIds)):
if OneWireIds[n] == sensorId:
return
OneWireIds.append(sensorId)
Domoticz.Device(Name="1-wire sensor #"+str(len(OneWireIds)), Unit=24+len(OneWireIds)-1, TypeName="Temperature", Options=sensorId).Create()
Domoticz.Log("New 1-wire temp sensor found and added, id "+str(sensorId))
return
Re: UniPi plugin - question
Posted: Friday 10 March 2017 14:29
by BlackSoll
Just test it and plugin works really great. Do you have any update for the digital inputs ?
Re: UniPi plugin - question
Posted: Saturday 11 March 2017 7:27
by ubee
No, not yet....
Re: UniPi plugin - question
Posted: Sunday 05 November 2017 16:00
by East
I have had this plugin running on Raspbian Jessie, and thanks for that!
Now I have the latest Raspbian Stretch and latest UniPi EVOK installed, and offcourse fresh Domoticz.
Installed the plugin from above and Domoticz shows the 8 relays but can not control them or even show their correct status.
What am I doing wrong?
Thanks in advance!
Log shows:
2017-11-05 13:43:29.920 User: Admin initiated a switch command (1/Relay 1/On)
2017-11-05 13:43:29.963 (UniPI) onCommand called for Unit 1: Parameter 'On', Level: 0
2017-11-05 13:43:29.968 Error: (UniPI) 'onCommand' failed 'URLError'.
2017-11-05 13:43:29.968 Error: (UniPI) ----> Line 130 in /home/pi/domoticz/plugins/UniPIx/plugin.py, function onCommand
2017-11-05 13:43:29.968 Error: (UniPI) ----> Line 232 in /home/pi/domoticz/plugins/UniPIx/plugin.py, function RelaySet
2017-11-05 13:43:29.968 Error: (UniPI) ----> Line 163 in /usr/lib/python3.5/urllib/request.py, function urlopen
2017-11-05 13:43:29.968 Error: (UniPI) ----> Line 466 in /usr/lib/python3.5/urllib/request.py, function open
2017-11-05 13:43:29.968 Error: (UniPI) ----> Line 484 in /usr/lib/python3.5/urllib/request.py, function _open
2017-11-05 13:43:29.968 Error: (UniPI) ----> Line 444 in /usr/lib/python3.5/urllib/request.py, function _call_chain
2017-11-05 13:43:29.968 Error: (UniPI) ----> Line 1282 in /usr/lib/python3.5/urllib/request.py, function http_open
2017-11-05 13:43:29.968 Error: (UniPI) ----> Line 1260 in /usr/lib/python3.5/urllib/request.py, function do_open
2017-11-05 13:43:33.425 (UniPI) onHeartbeat called
2017-11-05 13:43:33.429 Error: (UniPI) 'onHeartbeat' failed 'URLError'.
2017-11-05 13:43:33.429 Error: (UniPI) ----> Line 164 in /home/pi/domoticz/plugins/UniPIx/plugin.py, function onHeartbeat
2017-11-05 13:43:33.429 Error: (UniPI) ----> Line 163 in /usr/lib/python3.5/urllib/request.py, function urlopen
2017-11-05 13:43:33.429 Error: (UniPI) ----> Line 466 in /usr/lib/python3.5/urllib/request.py, function open
2017-11-05 13:43:33.429 Error: (UniPI) ----> Line 484 in /usr/lib/python3.5/urllib/request.py, function _open
2017-11-05 13:43:33.429 Error: (UniPI) ----> Line 444 in /usr/lib/python3.5/urllib/request.py, function _call_chain
2017-11-05 13:43:33.429 Error: (UniPI) ----> Line 1282 in /usr/lib/python3.5/urllib/request.py, function http_open
2017-11-05 13:43:33.429 Error: (UniPI) ----> Line 1260 in /usr/lib/python3.5/urllib/request.py, function do_open
Re: UniPi plugin - question
Posted: Thursday 09 November 2017 14:55
by guidovan3L
Hi,
I think your evok.conf needs some attention, the urlOpen function chokes on a hostname or IP being wrong.
Good Luck!
Re: UniPi plugin - question
Posted: Tuesday 27 February 2018 21:12
by palnic
Thank you! It works on Raspberry Stretch
Re: UniPi plugin - question
Posted: Thursday 03 May 2018 22:37
by Blindmouse
@Ubee
Can anyone help me?
I would like to run this script on a unipi neuron 203 device,with no 8 but 20 relays. Will this work for me? Do you have to modify something?
Re: UniPi plugin - question
Posted: Saturday 12 May 2018 21:20
by Blindmouse
@ East
Do you bet what the solution was? I am currently in a similar situation.

Re: UniPi plugin - question
Posted: Thursday 17 May 2018 20:36
by johnswinnen
Hi,
I just installed the plugin but after I create the hardware in Domoticz, Domoticz crashes ......
EVOK is running fine.
I use Domoticz Beta v3.9446
Anyone an idea?
Regards,
John
Re: UniPi plugin - question
Posted: Wednesday 09 September 2020 20:43
by kniferider
I have had this plugin running on Raspberry 3, with latest UniPi EVOK installed, and Domoticz.
Installed the plugin from above and Domoticz shows the 8 relays but can not control them or even show their correct status.
What am I doing wrong?
Thanks in advance!
Log shows:
2020-09-09 20:42:12.842 (UniPiboard) onHeartbeat called
2020-09-09 20:42:12.859 Error: (UniPiboard) 'onHeartbeat' failed 'URLError'.
2020-09-09 20:42:12.859 Error: (UniPiboard) ----> Line 164 in '/home/pi/domoticz/plugins/UniPIx/plugin.py', function onHeartbeat
2020-09-09 20:42:12.859 Error: (UniPiboard) ----> Line 222 in '/usr/lib/python3.7/urllib/request.py', function urlopen
2020-09-09 20:42:12.859 Error: (UniPiboard) ----> Line 525 in '/usr/lib/python3.7/urllib/request.py', function open
2020-09-09 20:42:12.859 Error: (UniPiboard) ----> Line 543 in '/usr/lib/python3.7/urllib/request.py', function _open
2020-09-09 20:42:12.859 Error: (UniPiboard) ----> Line 503 in '/usr/lib/python3.7/urllib/request.py', function _call_chain
2020-09-09 20:42:12.859 Error: (UniPiboard) ----> Line 1345 in '/usr/lib/python3.7/urllib/request.py', function http_open
2020-09-09 20:42:12.859 Error: (UniPiboard) ----> Line 1323 in '/usr/lib/python3.7/urllib/request.py', function do_open
Re: UniPi plugin - question
Posted: Tuesday 15 December 2020 18:50
by BlackSoll
Good news guys !!!!
Check here :
https://github.com/mccwdev/domoticz-unipi
Go at domoticz/plugins and make a new directory named UniPi.
Download the plugin.py file from the link above and copy it into the domoticz/plugins/UniPi directory.
Go to you domoticz and from hardware choose unipi evok plugin and fill your evok info.
Enjoy !!!