UniPi plugin - question

Python and python framework

Moderator: leecollings

Post Reply
ubee
Posts: 66
Joined: Tuesday 10 February 2015 20:38
Target OS: Raspberry Pi / ODroid
Domoticz version: 2021.1
Location: Sweden
Contact:

UniPi plugin - question

Post 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?
User avatar
Dnpwwo
Posts: 820
Joined: Sunday 23 March 2014 9:00
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Melbourne, Australia
Contact:

Re: UniPi plugin - question

Post 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.
The reasonable man adapts himself to the world; the unreasonable one persists to adapt the world to himself. Therefore all progress depends on the unreasonable man. George Bernard Shaw
ubee
Posts: 66
Joined: Tuesday 10 February 2015 20:38
Target OS: Raspberry Pi / ODroid
Domoticz version: 2021.1
Location: Sweden
Contact:

Re: UniPi plugin - question

Post 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.
jcmschoot
Posts: 1
Joined: Monday 13 February 2017 22:22
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Oosterhout Netherlands
Contact:

Re: UniPi plugin - question

Post 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..
User avatar
Dnpwwo
Posts: 820
Joined: Sunday 23 March 2014 9:00
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Melbourne, Australia
Contact:

Re: UniPi plugin - question

Post 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.
The reasonable man adapts himself to the world; the unreasonable one persists to adapt the world to himself. Therefore all progress depends on the unreasonable man. George Bernard Shaw
swevm
Posts: 23
Joined: Friday 16 September 2016 20:04
Target OS: Raspberry Pi / ODroid
Domoticz version: 8718
Location: Sweden
Contact:

Re: UniPi plugin - question

Post by swevm »

Interesting. :D

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.
Domoticz on RPi3 with Razberry: 10xZME WALLC-S, 14x Fib Switch, 6x Fib Wallplug, 1x Fib Motion Sensor, 2x Fib Smoke Sensor, 1x Fib Universal sensor (with 1-wire), 3x SwiidInter cordsw, ESPEasy [1-wire and relay], Kodi, Node-Red [Onkyo NR-828, UI etc]
ubee
Posts: 66
Joined: Tuesday 10 February 2015 20:38
Target OS: Raspberry Pi / ODroid
Domoticz version: 2021.1
Location: Sweden
Contact:

Re: UniPi plugin - question

Post 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
BlackSoll
Posts: 4
Joined: Sunday 12 July 2015 11:31
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.5877
Contact:

Re: UniPi plugin - question

Post by BlackSoll »

Just test it and plugin works really great. Do you have any update for the digital inputs ?
ubee
Posts: 66
Joined: Tuesday 10 February 2015 20:38
Target OS: Raspberry Pi / ODroid
Domoticz version: 2021.1
Location: Sweden
Contact:

Re: UniPi plugin - question

Post by ubee »

No, not yet....
East
Posts: 1
Joined: Sunday 05 November 2017 15:51
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: UniPi plugin - question

Post 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
guidovan3L
Posts: 1
Joined: Thursday 09 November 2017 14:38
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: UniPi plugin - question

Post by guidovan3L »

Hi,

I think your evok.conf needs some attention, the urlOpen function chokes on a hostname or IP being wrong.

Good Luck!
palnic
Posts: 36
Joined: Wednesday 13 September 2017 15:40
Target OS: Raspberry Pi / ODroid
Domoticz version: V3.8153
Location: Chicago
Contact:

Re: UniPi plugin - question

Post by palnic »

Thank you! It works on Raspberry Stretch
Blindmouse
Posts: 2
Joined: Thursday 03 May 2018 22:23
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.8153
Location: Hungary
Contact:

Re: UniPi plugin - question

Post 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?
Blindmouse
Posts: 2
Joined: Thursday 03 May 2018 22:23
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.8153
Location: Hungary
Contact:

Re: UniPi plugin - question

Post by Blindmouse »

@ East
Do you bet what the solution was? I am currently in a similar situation. :D :D :D
johnswinnen
Posts: 3
Joined: Thursday 17 May 2018 20:34
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: UniPi plugin - question

Post 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
kniferider
Posts: 1
Joined: Tuesday 09 June 2020 10:25
Target OS: -
Domoticz version:
Contact:

Re: UniPi plugin - question

Post 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
BlackSoll
Posts: 4
Joined: Sunday 12 July 2015 11:31
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.5877
Contact:

Re: UniPi plugin - question

Post 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 !!!
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest