Page 2 of 5

Re: Python Plugin: WLED

Posted: Wednesday 27 November 2019 21:50
by Ankan
I have found the problem and fixed it by converting Color to string.

Row 237:
Changed from: Devices[Unit].Update(nValue=nValue, sValue=str(sValue), Color=Color)
Changed to: Devices[Unit].Update(nValue=nValue, sValue=str(sValue), Color=str(Color))

Re: Python Plugin: WLED

Posted: Wednesday 27 November 2019 22:01
by Ankan
Maye the true ploblem is this:
The Color parameter is valid if Command is "Set Color" and is a JSON serialized Domoticz color object.
Quoted from https://www.domoticz.com/wiki/Developin ... hon_plugin

Re: Python Plugin: WLED

Posted: Wednesday 27 November 2019 22:13
by Ankan
Instead of changing row 237 I changed the calling rows instead:

Row 145:
From: UpdateDevice(3,1,self.Level,self.Color)
To: UpdateDevice(3,1,self.Level)

Row 157:
From: UpdateDevice(3,1,self.Level,self.Color)
To: UpdateDevice(3,1,self.Level)

Row 161:
From: UpdateDevice(3,0,self.Level,self.Color)
To: UpdateDevice(3,0,self.Level)

Re: Python Plugin: WLED

Posted: Wednesday 27 November 2019 23:05
by frustreerMeneer
Ankan wrote: Wednesday 27 November 2019 22:13 Instead of changing row 237 I changed the calling rows instead:

Row 145:
From: UpdateDevice(3,1,self.Level,self.Color)
To: UpdateDevice(3,1,self.Level)

Row 157:
From: UpdateDevice(3,1,self.Level,self.Color)
To: UpdateDevice(3,1,self.Level)

Row 161:
From: UpdateDevice(3,0,self.Level,self.Color)
To: UpdateDevice(3,0,self.Level)
Thanks! I have changed it and will test it for a while.

Re: Python Plugin: WLED

Posted: Wednesday 27 November 2019 23:29
by Ankan
If you don't set the color you should not send that argument to Devices[Unit].Update()

So you have to change the code little bit more. Maybe check if color is set and then call Update with or without color argument.

Else maybe you could overload the UpdateDevice function. One with 3 arguments and one with 4 arguments.

Re: Python Plugin: WLED

Posted: Monday 02 December 2019 19:56
by Ankan
I got stability problems with my system after installing your plugin. Maybe it's because it connect to the WLED on every heartbeat.
You can see the problem in the log for the device. I have only enabled "Color & Brightness".

My log looks like this without doing anything:

Code: Select all

2019-12-02 19:44:27	On
2019-12-02 19:44:17	On
2019-12-02 19:44:07	On
2019-12-02 19:43:56	On
2019-12-02 19:43:46	On
2019-12-02 19:43:36	On
2019-12-02 19:43:26	On
2019-12-02 19:43:16	On
2019-12-02 19:43:06	On
2019-12-02 19:42:56	On
2019-12-02 19:42:46	On
2019-12-02 19:42:36	On
2019-12-02 19:42:26	On
2019-12-02 19:42:16	On
2019-12-02 19:42:06	On
I guess you get this on onHertbeat callback every 10s. Maybe you don't have to do anything on heartbeat as long as you don't control your WLED strip from the WLED app or website.

Re: Python Plugin: WLED

Posted: Monday 02 December 2019 20:23
by frustreerMeneer
Ankan wrote: Monday 02 December 2019 19:56 I got stability problems with my system after installing your plugin. Maybe it's because it connect to the WLED on every heartbeat.
You can see the problem in the log for the device. I have only enabled "Color & Brightness".

My log looks like this without doing anything:

Code: Select all

2019-12-02 19:44:27	On
2019-12-02 19:44:17	On
2019-12-02 19:44:07	On
2019-12-02 19:43:56	On
2019-12-02 19:43:46	On
2019-12-02 19:43:36	On
2019-12-02 19:43:26	On
2019-12-02 19:43:16	On
2019-12-02 19:43:06	On
2019-12-02 19:42:56	On
2019-12-02 19:42:46	On
2019-12-02 19:42:36	On
2019-12-02 19:42:26	On
2019-12-02 19:42:16	On
2019-12-02 19:42:06	On
Are you sure the above notifications are caused by the WLED plugin?
Can you try the new version i uploaded yesterday? (You have to restart Domoticz after installing.)
Ankan wrote: Monday 02 December 2019 19:56 I guess you get this on onHeartbeat callback every 10s. Maybe you don't have to do anything on heartbeat as long as you don't control your WLED strip from the WLED app or website.
WLED doesn't actively let the plugin know something has changed. That is why the plugin updates the status every heartbeat. Otherwise changes in the app or website aren't reflected quickly in Domoticz.
Maybe that would be possible with UDP but i have not looked into that and have no experience with it.

I'll try to find out if i can detect changes in WLED so the plugin doesn't have to update Domoticz every heartbeat.

Re: Python Plugin: WLED

Posted: Monday 02 December 2019 20:41
by Ankan
Hi,

Yes, this log is from my system today after updating to latest version of your plugin. My device log stop adding On command every 10s after comment out onHeartbeat so the problem is there.

If you have to update every 10s you have to change the script to not update the domoticz device every time if there is no change. Else I guess you will have problems with events that trigger on wled device change.

Re: Python Plugin: WLED

Posted: Monday 02 December 2019 20:46
by kurczak2
Thanks for your hard work! The plugin works very well. It was useful to me just in time - before Christmas. Thanks again!

Re: Python Plugin: WLED

Posted: Monday 02 December 2019 21:42
by frustreerMeneer
Ankan wrote: Monday 02 December 2019 20:41 If you have to update every 10s you have to change the script to not update the domoticz device every time if there is no change. Else I guess you will have problems with events that trigger on wled device change.
I have updated the plugin to update Domoticz only when something changes.
Hope it works better for you now ;)

Re: Python Plugin: WLED

Posted: Monday 02 December 2019 21:54
by frustreerMeneer
kurczak2 wrote: Monday 02 December 2019 20:46 Thanks for your hard work! The plugin works very well. It was useful to me just in time - before Christmas. Thanks again!
Glad you like it! :D

Re: Python Plugin: WLED

Posted: Monday 02 December 2019 21:57
by Ankan
frustreerMeneer wrote: Monday 02 December 2019 21:42
Ankan wrote: Monday 02 December 2019 20:41 If you have to update every 10s you have to change the script to not update the domoticz device every time if there is no change. Else I guess you will have problems with events that trigger on wled device change.
I have updated the plugin to update Domoticz only when something changes.
Hope it works better for you now ;)
That is what I call good support.

Thanks, it looks better!

Re: Python Plugin: WLED

Posted: Tuesday 03 December 2019 22:05
by Ankan
Hi there. I found one more little bug you maybe could check up.

When turning on, off or dimming "WLED - Color & Brightness" in Domoticz, very often there are two lines in the device log.
If turning off the device I sometimes get:
2019-12-03 21:52:50 On
2019-12-03 21:52:47 Off

When turning on or dimming:
2019-12-03 21:52:10 On
2019-12-03 21:52:06 On

I guess you update the device in Domoticz when do a action on it and then update it again on Heartbeat to get into sync.
Best way would be if the WLED update domoticz and skip polling on every heartbeat. Maybe the problem is in the dimmer/brightness value as you convert from procent to 0-255 and then back on status request.

It would be nice to use WLED builtin sync function to update Domoticz.

Re: Python Plugin: WLED

Posted: Thursday 05 December 2019 11:12
by frustreerMeneer
Ankan wrote: Tuesday 03 December 2019 22:05 It would be nice to use WLED builtin sync function to update Domoticz.
I'm looking at the UDP sync but can't get Domoticz to listen yet.
When i have more time i will dive into it ;-)

Re: Python Plugin: WLED

Posted: Thursday 05 December 2019 13:03
by Ankan

Re: Python Plugin: WLED

Posted: Saturday 07 December 2019 11:04
by Ankan
Hi,

I think I have something for you. The code now listen to UDP Sync port and update devices from it.
I think it need some more testing but it's a good start. Enjoy!

Code: Select all

# WLED Plugin for Domoticz
#
# Author: Frustreermeneer
#
"""
<plugin key="WLED2" name="WLED2" author="frustreermeneer" version="0.0.1" wikilink="http://www.domoticz.com/wiki/plugins/plugin.html" externallink="https://github.com/frustreermeneer/domoticz-wled-plugin">
	<description>
		<h2>WLED Plugin</h2><br/>
		<h3>Features</h3>
		<ul style="list-style-type:square">
			<li>Switching WLED on/off</li>
			<li>Setting brightness</li>
			<li>Setting effect from list</li>
			<li>Setting effect speed & intensity</li>
			<li>Setting presets from list</li>
			<li>Setting palette from list</li>
		</ul>
		<h3>Configuration</h3>
	</description>
	<params>
		<param field="Address" label="WLED IP Address" width="200px" required="true" default=""/>
		<param field="Port" label="WLED UDP Sync Port" width="200px" required="true" default=""/>
		<param field="Mode6" label="Debug" width="150px">
			<options>
				<option label="None" value="0"  default="true" />
				<option label="Python Only" value="2"/>
				<option label="Basic Debugging" value="62"/>
				<option label="Basic+Messages" value="126"/>
				<option label="Connections Only" value="16"/>
				<option label="Connections+Queue" value="144"/>
				<option label="All" value="-1"/>
			</options>
		</param>
	</params>
</plugin>
"""
import Domoticz
import requests
import json

sAddress = ""
sPort = ""
wledData = None
jsonArray = None

class BasePlugin:
	BeaconConn = None
	getWLEDStatusConn = None
	
	def __init__(self):
		return

	def onStart(self):
		self.counter = 0
		self.Color = {}
		self.Level = 100

		global sAddress
		global sPort

		sAddress = Parameters["Address"].strip()
		sPort = Parameters["Port"].strip()

		if Parameters["Mode6"] != "0":
			Domoticz.Debugging(int(Parameters["Mode6"]))
			DumpConfigToLog()
		
		if (len(Devices) == 0):
			Domoticz.Log("creating devices")

			Options = {"LevelActions": "",
				  "LevelNames": "Loading...",
				  "LevelOffHidden": "true",
				  "SelectorStyle": "1"}

			Domoticz.Device(Name="Palettes", Unit=1, TypeName="Selector Switch", Options=Options, Image=0).Create()
			Domoticz.Device(Name="Effects", Unit=2, TypeName="Selector Switch", Options=Options).Create()
			Domoticz.Device(Name="Color & Brightness", Unit=3, Type=241,Subtype=2,Switchtype=7,Options=Options).Create()
			Domoticz.Device(Name="Presets", Unit=4, TypeName="Selector Switch", Options=Options).Create()
			Domoticz.Device(Name="FX Speed", Unit=5, Type=244,Subtype=62,Switchtype=7,Options=Options).Create()
			Domoticz.Device(Name="FX Intensity", Unit=6, Type=244,Subtype=62,Switchtype=7,Options=Options).Create()
		else:
			Domoticz.Log("devices existed already")

		UpdatePresetsInDomoticz()
		
		self.getWLEDStatusConn = Domoticz.Connection(Name="getWLEDStatusConn", Transport="TCP/IP", Protocol="HTTP", Address=sAddress, Port="80" )
		self.getWLEDStatusConn.Connect()
	
		self.BeaconConn = Domoticz.Connection(Name="Beacon", Transport="UDP/IP", Address=sAddress, Port=str(sPort))
		self.BeaconConn.Listen()


	def onConnect(self, Connection, Status, Description):
		global sAddress
 
		# er is een externe verbinding gemaakt
		# json request doen
		if( Connection.Name == "getWLEDStatusConn" ):
			sendData = { 'Verb' : 'GET',
						 'URL'  : '/json',
						 'Headers' : { 'Content-Type': 'application/json; charset=utf-8', 
									   'Connection': 'close', 
									   'Accept': 'Content-Type: text/plain; charset=UTF-8', 
									   'Host': sAddress+":80",
									   'User-Agent':'Domoticz/1.0' }
					   }
			Connection.Send(sendData)


	def onMessage(self, Connection, Data):
	
		global wledData
		global jsonArray
	
		try:
			# we krijgen antwoord terug op onze request
			# json update request afhandelen
			if( Connection.Name == "getWLEDStatusConn" ):
				Connection.Disconnect()
				
				Status = int(Data["Status"])
				
				if( Status == 200 ):
					strData = Data["Data"].decode("utf-8", "ignore")

					jsonArray = json.loads( str(strData) ) 

					if( len( jsonArray ) ):
						UpdateEffectsInDomoticz()
						UpdatePalettesInDomoticz()
		
		
			if (Connection.Name == "Beacon"):
				Domoticz.Debug("Connection detail: "+str(Connection))
				
				# Is it notifier protocol
				if ( Data[0] == 0x00 and Data[21] == 0x00 and Data[22] == 0x00 and Data[23] == 0x00 and Data[24] == 0x00):
					wledData = {
						"callMode": Data[1],
						"bri": Data[2],
						"red": Data[3],
						"green": Data[4],
						"blue": Data[5],
						"nightlightActive": Data[6],
						"nightlightDelayMins": Data[7],
						"effectCurrent": Data[8],
						"effectSpeed": Data[9],
						"white": Data[10],
						"redSec": Data[12],
						"greenSec": Data[13],
						"blueSec": Data[14],
						"whiteSec": Data[15],
						"effectIntensity": Data[16],
						"transitionDelayHi": Data[17],
						"transitionDelayLow": Data[18],
						"effectPalette": Data[19]
					}
					
					UpdateStatusInDomoticz()

		except Exception as inst:
			Domoticz.Error("Exception detail: '"+str(inst)+"'")
			raise

	def onCommand(self, Unit, Command, Level, Color):
#		Domoticz.Log("onCommand called for Unit " + str(Unit) + ": Command '" + str(Command) + "', Level: " + str(Level) + "', Color: " + str(Color) )

		# palettes keuze
		if( Unit == 1 ):
			if( Command == "Set Level" ):
				doWLEDRequest( "&FP="+str(int(Level/10)-1) )
	
		# effect keuze

		if( Unit == 2 ):
			if( Command == "Set Level" ):
				doWLEDRequest( "&T=1&FX="+str(int(Level/10)-1) )

			if( Command == "Off" ):
				doWLEDRequest( "&T=0" )

		# kleurkeuze 

		if( Unit == 3 ):
			if( Command == "Set Level" ):
				self.Level = Level if Level < 100 else 100
				doWLEDRequest( "/win&A="+str(int(self.Level*2.55)) )

			if( Command == "Set Color" ):		#set kleur en level
				self.Color = Color;
				self.Level = Level
				Domoticz.Log( "Color:" + str(self.Color) )
				parsedColor = json.loads(self.Color)
				doWLEDRequest( "/win&FX=0&A="+str(int(self.Level*2.55))+"&R="+str(parsedColor["r"])+"&G="+str(parsedColor["g"])+"&B="+str(parsedColor["b"] ) )

			if( Command == "On" ):
				doWLEDRequest( "/win&T=1&A="+str(int(self.Level*2.55)) )

			if( Command == "Off" ):
				doWLEDRequest( "/win&T=0&A="+str(int(self.Level*2.55)) )

		# preset keuze
		if( Unit == 4 ):
			if( Command == "Set Level" ):
				Domoticz.Log( "Switching to preset" + str(int(Level/10)))
				doWLEDRequest( "/win&PL="+str(int(Level/10)) )

		# fx speed
		if( Unit == 5 ):
			if( Command == "Set Level" ):
				Domoticz.Log( "FX Speed: " + str(int(Level*2.55)))
				doWLEDRequest( "/win&SX="+str(int(Level*2.55)) )

		# fx intensity
		if( Unit == 6 ):
			if( Command == "Set Level" ):
				Domoticz.Log( "FX Intensity: " + str(int(Level*2.55)))
#				UpdateDevice(6,1,int(Level))
				doWLEDRequest( "/win&IX="+str(int(Level*2.55)) )


global _plugin
_plugin = BasePlugin()

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

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, Hue):
	global _plugin
	_plugin.onCommand(Unit, Command, Level, Hue)

	# 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))
	return

def UpdateDevice(Unit, nValue, sValue, Color=""):
	# Make sure that the Domoticz device still exists (they can be deleted) before updating it.
	if (Unit in Devices):
		if (Devices[Unit].nValue != nValue) or (Devices[Unit].sValue != sValue) or (Devices[Unit].Color != Color):
			if( Color ):
				Devices[Unit].Update(nValue=nValue, sValue=str(sValue), Color=str(Color) )
			else:
				Devices[Unit].Update(nValue=nValue, sValue=str(sValue) )
	return

def UpdateEffectsInDomoticz():

#	Domoticz.Log("updateEffects")

	LevelNames = "Off|"
	LevelActions = "|"

	effectsArray = jsonArray["effects"]

	for idx,effect in enumerate(effectsArray):
		LevelNames = LevelNames + str(idx+1) + " - " + str(effect)
		if( idx < len(effectsArray)-1 ):
			LevelNames = LevelNames + "|"
			LevelActions = LevelActions + "|"

	dictOptions = Devices[2].Options
	dictOptions["LevelNames"] = LevelNames
	dictOptions["LevelActions"] = LevelActions
	nValue = Devices[2].nValue;
	sValue = Devices[2].sValue;
	Devices[2].Update(nValue = nValue, sValue = sValue, Options = dictOptions)

def UpdatePalettesInDomoticz():
	global jsonArray

#	Domoticz.Log("updatePallettes")

	LevelNames = "Off|"
	LevelActions = "|"

	palettesArray = jsonArray["palettes"]

	for idx,palette in enumerate(palettesArray):
		LevelNames = LevelNames + str(idx+1) + " - " + str(palette)
		if( idx < len(palettesArray)-1 ):
			LevelNames = LevelNames + "|"
			LevelActions = LevelActions + "|"

	dictOptions = Devices[1].Options
	dictOptions["LevelNames"] = LevelNames
	dictOptions["LevelActions"] = LevelActions
	nValue = Devices[1].nValue;
	sValue = Devices[1].sValue;
	Devices[1].Update(nValue = nValue, sValue = sValue, Options = dictOptions)


def UpdatePresetsInDomoticz():
#	Domoticz.Log("updatePresets")

	LevelNames = "None|"
	LevelActions = "|"

	for i in range(1,25):
		LevelNames = LevelNames + str(i)
		if( i < 24 ):
		   LevelNames = LevelNames + "|"
		   LevelActions = LevelActions + "|"

#	Domoticz.Log( LevelNames )

	dictOptions = Devices[4].Options
	dictOptions["LevelNames"] = LevelNames
	dictOptions["LevelActions"] = LevelActions
	dictOptions["LevelOffHidden"] = "false"
	nValue = Devices[4].nValue;
	sValue = Devices[4].sValue;
	Devices[4].Update(nValue = nValue, sValue = sValue, Options = dictOptions)

def UpdateStatusInDomoticz():
	global wledData

	brightness = wledData["bri"]
	r = wledData["red"]
	g = wledData["green"]
	b = wledData["blue"]
	color = json.dumps({ "b":b, "cw":0, "g":g, "m":3, "r":r, "t":0, "ww":0 })

	UpdateDevice(3,1,int(brightness/2.55),color) #Devices[3].sValue)

	UpdateDevice(6,1,wledData["effectIntensity"]/2.55)

	UpdateDevice(5,1,wledData["effectSpeed"]/2.55)
	
	effect = wledData["effectCurrent"]
	UpdateDevice(2,1,(effect+1)*10)

	UpdateDevice(1, 1, (wledData["effectPalette"]+1)*10 )

def doWLEDRequest( parameters ):
	global sAddress
	url = "http://"+sAddress+"/win"+parameters
#	Domoticz.Log( url )
	resp = requests.get(url=url)
#	Domoticz.Log(str(resp.status_code))
#	Domoticz.Log(str(resp))

I had to change name to WLED2 as I wanted both plugins run side by side

Re: Python Plugin: WLED

Posted: Monday 09 December 2019 15:01
by frustreerMeneer
Ankan wrote: Saturday 07 December 2019 11:04 Hi,

I think I have something for you. The code now listen to UDP Sync port and update devices from it.
I think it need some more testing but it's a good start. Enjoy!

I had to change name to WLED2 as I wanted both plugins run side by side
Thanks Ankan, i will check it out.
Apparently you had more success getting UDP to work.

I will have to figure out if UDP will be the only source for updates or not.
It depends on wether Aircoookie will keep the data in UDP and JSON the same.

Re: Python Plugin: WLED

Posted: Tuesday 10 December 2019 23:05
by frustreerMeneer
The latest version of the plugin now updates Domoticz status via UDP and is therefore much more efficient and faster.
Don't forget to restart Domoticz after updating and fill out the new sync settings.

Thanks for @Ankan for helping me out!

Re: Python Plugin: WLED

Posted: Tuesday 10 December 2019 23:16
by Ankan
Great!

By the way, I think you should change udp port to what the user enter in the configuration and not hardcode it.

Re: Python Plugin: WLED

Posted: Tuesday 10 December 2019 23:20
by frustreerMeneer
Ankan wrote: Tuesday 10 December 2019 23:16 By the way, I think you should change udp port to what the user enter in the configuration and not hardcode it.

Wow! You're fast and sharp ;)
I forgot to change it. Now fixed it.