beok thermostat plugin

Python and python framework

Moderator: leecollings

Post Reply
omeijers
Posts: 4
Joined: Monday 12 January 2015 19:48
Target OS: Raspberry Pi / ODroid
Domoticz version: 2022.2
Location: Malden, Netherlands
Contact:

beok thermostat plugin

Post by omeijers »

Hi, while creating a plugin for controlling a beok thermostat through broadlink protocol i run into problems trying to control the thermostat.
done so far:
1) create plugin
2) define hardware, this then creates the setpoint thermostat and temperature devices
3) on heartbeat poll the beok thermostat through broadlink and get the room temperature and the beok thermostat set temp
4) write these values to the log
5) update the temperature sensor with the room temp from the thermostat

this all works fine:
from log:
2022-12-20 16:08:59.071 Beokeroni: onHeartbeat called
2022-12-20 16:08:59.452 Beokeroni: room temp: 19.0 Thermostat set temp: 19.0


then the idea is to set the thermostat in domoticz and send the value to the beok thermostat and vice versa.
However, what puzzles me the when i try to set the domoticz thermostats, it generates an error in the log and does not update the value
from log:
2022-12-20 15:50:52.378 Error: Beokeroni: Call to function 'onCommand' failed, exception details:
2022-12-20 15:50:52.380 Error: Beokeroni: Exception: 'TypeError'. No traceback available.


I am a bit at a loss here, any suggestions?
basically I would like to send domoticz thermostat setpoint to the beok thermostat and vice versa.
in which functions do I need to implement this.

below the plugin sofar:

Code: Select all

# Basic Python Plugin Example
#
# Author: GizMoCuz
#

"""
<plugin key="Beok" name="Beok Thermostat" author="Onno Meijers" version="1.0.0">
    <description>
        <h2>Beok Thermostat Interface</h2><br/>
    </description>
    <params>
        <param field="Address" label="IP Address" width="200px" required="true"/>
        <param field="Port" label="Port" width="30px" required="true"/>
        <param field="Mode1" label="MAC Address" width="200px" required="true">
            <description>e.g. XX:XX:XX:...</description>
        </param>
        <param field="Mode2" label="Type" width="50px" required="true"/>
    </params>
</plugin>
"""

import Domoticz
import broadlink

class BasePlugin:
    enabled = False
    def __init__(self):
        #self.var = 123
        return

    def onStart(self):
        # thermostat ip and mac address
        ip = Parameters['Address']
        port = int(Parameters['Port'])
        host_mac = Parameters['Mode1']
        type = int(Parameters['Mode2']) # Thermostat type
        # Convert the mac address to bytes (from hex)
        mac_bytes = bytearray.fromhex(host_mac.replace(':',''))
        # Establish the device
        self.thermostat = broadlink.hysen((ip,port), mac_bytes, type)
        # Authenticate yourself
        self.thermostat.auth()

        # Check if devices need to be created
        createDevices()

    
    def onStop(self):
        Domoticz.Log("onStop called")

    def onConnect(self, Connection, Status, Description):
        Domoticz.Log("onConnect called")

    def onMessage(self, Connection, Data):
        Domoticz.Log("onMessage called")

    def onCommand(self, DeviceID, Unit, Command, Level, Color):
        Domoticz.Log("onCommand called for Device " + str(DeviceID) + " Unit " + str(Unit) + ": Parameter '" + str(Command) + "', Level: " + str(Level))
        
        
    
    def onNotification(self, Name, Subject, Text, Status, Priority, Sound, ImageFile):
        Domoticz.Log("Notification: " + Name + "," + Subject + "," + Text + "," + Status + "," + str(Priority) + "," + Sound + "," + ImageFile)

    def onDisconnect(self, Connection):
        Domoticz.Log("onDisconnect called")

    def onHeartbeat(self):
        Domoticz.Log("onHeartbeat called")
        # get set_temp from thermostat and call it : thermostat_set_temp
        data = str(self.thermostat.get_full_status())
        start_st = int(data.find('thermostat_temp')+18)
        end_st = int(data.find('thermostat_temp') +22)
        thermostat_set_temp = data[start_st:end_st]    
        Domoticz.Log("room temp: " + str(self.thermostat.get_temp()) + " Thermostat set temp: " + thermostat_set_temp)
        Devices[2].Update(nValue=int(), sValue=str(self.thermostat.get_temp()))
        #Devices[1].Update(nvalue=int(),sValue=str(thermostat_set_temp))

        #lets check if we can read the  domoticz thermostat setting,  no luck here
        Domoticz_thermos_settemp=Devices[1].sValue
        Domoticz.Log("set temp: " + Domoticz_thermos_settemp)

global _plugin
_plugin = BasePlugin()

def onStart():
    global _plugin
    _plugin.onStart()

def onStop():
    global _plugin
    _plugin.onStop()

def onConnect(Connection, Status, Description):
    global _plugin
    _plugin.onConnect(Connection, Status, Description)

def onMessage(Connection, Data):
    global _plugin
    _plugin.onMessage(Connection, Data)

def onCommand(DeviceID, Unit, Command, Level, Color):
    global _plugin
    _plugin.onCommand(DeviceID, Unit, Command, Level, Color)

def onNotification(Name, Subject, Text, Status, Priority, Sound, ImageFile):
    global _plugin
    _plugin.onNotification(Name, Subject, Text, Status, Priority, Sound, ImageFile)

def onDisconnect(Connection):
    global _plugin
    _plugin.onDisconnect(Connection)

def onHeartbeat():
    global _plugin
    _plugin.onHeartbeat()

# 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 DeviceName in Devices:
        Device = Devices[DeviceName]
        Domoticz.Debug("Device ID:       '" + str(Device.DeviceID) + "'")
        Domoticz.Debug("--->Unit Count:      '" + str(len(Device.Units)) + "'")
        for UnitNo in Device.Units:
            Unit = Device.Units[UnitNo]
            Domoticz.Debug("--->Unit:           " + str(UnitNo))
            Domoticz.Debug("--->Unit Name:     '" + Unit.Name + "'")
            Domoticz.Debug("--->Unit nValue:    " + str(Unit.nValue))
            Domoticz.Debug("--->Unit sValue:   '" + Unit.sValue + "'")
            Domoticz.Debug("--->Unit LastLevel: " + str(Unit.LastLevel))
    return


#############################################################################
#                       Device specific functions                           #
#############################################################################

def createDevices():

    # Are there any devices?
    ###if len(Devices) != 0:
    # Could be the user deleted some devices, so do nothing
    ###return

    # Give the devices a unique unit number. This makes updating them more easy.
    # UpdateDevice() checks if the device exists before trying to update it.
    if (len(Devices) == 0):
        Domoticz.Device(Name="Thermostat", Unit=1, Type=242, Subtype=1, Used=1).Create()
        Domoticz.Log("Thermostat Device created.")
        Domoticz.Device(Name="RoomTemp", Unit=2, TypeName="Temperature", Used=1).Create()
        Domoticz.Log("RoomTemp Device created.")

omeijers
Posts: 4
Joined: Monday 12 January 2015 19:48
Target OS: Raspberry Pi / ODroid
Domoticz version: 2022.2
Location: Malden, Netherlands
Contact:

Re: beok thermostat plugin

Post by omeijers »

Got it to work, finally...
problem as I see it was with the example plugin I used as template, its the extended framework. while I used the Legacy commands.
For now no more help needed.

below the first working version:

Code: Select all

#  plugin to control beok thermostat
#  very rough draft, new to phyton and plugins so no garantees
#  the plugin uses broadlink to connect to the beok thermostat, read room temp and setpoint temp
#  roomtemp is published in Domoticz 
#  when setpoint is changed on beok thermostat it updates the domotics setpoint and vice versa


"""
<plugin key="Beok" name="Beok Thermostat" author="Onno Meijers" version="1.0.0">
    <description>
        <h2>Beok Thermostat Interface</h2><br/>
    </description>
    <params>
        <param field="Address" label="IP Address" width="200px" required="true"/>
        <param field="Port" label="Port" width="30px" required="true"/>
        <param field="Mode1" label="MAC Address" width="200px" required="true">
            <description>e.g. XX:XX:XX:...</description>
        </param>
        <param field="Mode2" label="Type" width="50px" required="true"/>
    </params>
</plugin>
"""

import Domoticz   
import broadlink

class BasePlugin:
    enabled = False
    def __init__(self):
        #self.var = 123
        return

    def onStart(self):
        # thermostat ip and mac address
        ip = Parameters['Address']
        port = int(Parameters['Port'])
        host_mac = Parameters['Mode1']
        type = int(Parameters['Mode2']) # Thermostat type
        # Convert the mac address to bytes (from hex)
        mac_bytes = bytearray.fromhex(host_mac.replace(':',''))
        # Establish the device
        self.thermostat = broadlink.hysen((ip,port), mac_bytes, type)
        # Authenticate yourself
        self.thermostat.auth()

        # Check if devices need to be created
        createDevices()
        
    
    def onStop(self):
        Domoticz.Log("onStop called")

    def onConnect(self, Connection, Status, Description):
        Domoticz.Log("onConnect called")

    def onMessage(self, Connection, Data):
        Domoticz.Log("onMessage called")

    #this is original onCommand thingy.  No functione, probably DomoticzEx speak
    #def onCommand(self, DeviceID, Unit, Command, Level, Color):
    #    Domoticz.Log("onCommand called")
    #    Domoticz.Log("onCommand called for Device " + str(DeviceID) + " Unit " + str(Unit) + ": Parameter '" + str(Command) + "', Level: " + str(Level))
    
    def onCommand(self, Unit, Command, Level, Color):
        Domoticz.Log("onCommand called")
        Domoticz.Log("onCommand called for Unit {}: Command '{}', Level: {}".format(Unit, Command, Level))

        #Now write the new value to the domoticz thermostat and beok thermostat
        Devices[1].Update(10, str(Level))
        self.thermostat.set_temp(Level)

    def onNotification(self, Name, Subject, Text, Status, Priority, Sound, ImageFile):
        Domoticz.Log("Notification: " + Name + "," + Subject + "," + Text + "," + Status + "," + str(Priority) + "," + Sound + "," + ImageFile)

    def onDisconnect(self, Connection):
        Domoticz.Log("onDisconnect called")

    def onHeartbeat(self):
        Domoticz.Log("onHeartbeat called")
        # get set_temp from thermostat and call it : thermostat_set_temp
        data = str(self.thermostat.get_full_status())
        start_st = int(data.find('thermostat_temp')+18)
        end_st = int(data.find('thermostat_temp') +22)
        thermostat_set_temp = data[start_st:end_st]    
        Domoticz.Log("room temp: " + str(self.thermostat.get_temp()) + " Thermostat set temp: " + thermostat_set_temp)
        
        #write beok room temp and beok thermostat setpoint to domoticz devices
        Devices[2].Update(10, str(self.thermostat.get_temp()))
        Devices[1].Update(10, str(thermostat_set_temp))



global _plugin
_plugin = BasePlugin()

def onStart():
    global _plugin
    _plugin.onStart()

def onStop():
    global _plugin
    _plugin.onStop()

def onConnect(Connection, Status, Description):
    global _plugin
    _plugin.onConnect(Connection, Status, Description)

def onMessage(Connection, Data):
    global _plugin
    _plugin.onMessage(Connection, Data)

def onCommand(Unit, Command, Level, Color):
    global _plugin
    _plugin.onCommand(Unit, Command, Level, Color)

#this is the original onCommand thingy
#def onCommand(DeviceID, Unit, Command, Level, Color):
#    global _plugin
#    _plugin.onCommand(DeviceID, Unit, Command, Level, Color)

def onNotification(Name, Subject, Text, Status, Priority, Sound, ImageFile):
    global _plugin
    _plugin.onNotification(Name, Subject, Text, Status, Priority, Sound, ImageFile)

def onDisconnect(Connection):
    global _plugin
    _plugin.onDisconnect(Connection)

def onHeartbeat():
    global _plugin
    _plugin.onHeartbeat()

# 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 DeviceName in Devices:
        Device = Devices[DeviceName]
        Domoticz.Debug("Device ID:       '" + str(Device.DeviceID) + "'")
        Domoticz.Debug("--->Unit Count:      '" + str(len(Device.Units)) + "'")
        for UnitNo in Device.Units:
            Unit = Device.Units[UnitNo]
            Domoticz.Debug("--->Unit:           " + str(UnitNo))
            Domoticz.Debug("--->Unit Name:     '" + Unit.Name + "'")
            Domoticz.Debug("--->Unit nValue:    " + str(Unit.nValue))
            Domoticz.Debug("--->Unit sValue:   '" + Unit.sValue + "'")
            Domoticz.Debug("--->Unit LastLevel: " + str(Unit.LastLevel))
    return


#############################################################################
#                       Device specific functions                           #
#############################################################################

def createDevices():

    # Are there any devices?
    ###if len(Devices) != 0:
    # Could be the user deleted some devices, so do nothing
    ###return

    # Give the devices a unique unit number. This makes updating them more easy.
    # UpdateDevice() checks if the device exists before trying to update it.
    if (len(Devices) == 0):    
        Domoticz.Device(Name="Thermostat", Unit=1, Type=242, Subtype=1, Used=1).Create()
        Domoticz.Log("Thermostat Device created.")
        Domoticz.Device(Name="RoomTemp", Unit=2, TypeName="Temperature", Used=1).Create()
        Domoticz.Log("RoomTemp Device created.")

redguyz
Posts: 1
Joined: Sunday 29 January 2023 14:55
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: beok thermostat plugin

Post by redguyz »

Congrats omeijers. Great to have it work. Very useful for many Domoticz users like me, I think. One more thing has to be corrected. When there is no connection to one of the thermostats, the plugin generates errors. Which sooner or later crash the Domoticz system. Accordingly Domoticz have to be restarted. It'll be good if this not happen. But no idea how to be done.
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest