Thanks, this helps a lot.
Setting patterns by name is now working as expected.
I had several other commands to update, but I believe I have everything working that I need.
It appears that waitForEmptyQueue is no longer needed, as is a pb.Close() command.
It appears that you can get the ID of the current Pattern with getActivePattern(), but there doesn’t seem to be a way to get the name of this pattern. I’d humbly suggest this be added to the list of future possible improvements, should I not be missing it somewhere, as it would be helpful to see on the user end. - edit: I recognize it is referenced in getSequencerState, and could likely be extracted from this
My testing showed some combination of back-to-back requesting getStorageSize(), getStorageUsed(), getUptime(), and/or getVersion() command seemed to timeout or crash the system - there may be a problem there. If I removed those requests from my currentState function, then things seemed to run as expected.
^C resulted in the following traceback:
^CTraceback (most recent call last):
File “/var/lib/openhab/PBScript.py”, line 234, in
currentState()
File “/var/lib/openhab/PBScript.py”, line 148, in currentState
print("Current firmware version : ", pb.getVersion())
File “/var/lib/openhab/pixelblaze.py”, line 1800, in getVersion
self.latestVersion = self.getConfigSettings().get(‘ver’, None)
File “/var/lib/openhab/pixelblaze.py”, line 1302, in getConfigSettings
ignored = self.wsReceive(binaryMessageType=None)
File “/var/lib/openhab/pixelblaze.py”, line 437, in wsReceive
frame = self.ws.recv()
File “/home/openhabian/.local/lib/python3.10/site-packages/websocket/_core.py”, line 362, in recv
opcode, data = self.recv_data()
File “/home/openhabian/.local/lib/python3.10/site-packages/websocket/_core.py”, line 385, in recv_data
opcode, frame = self.recv_data_frame(control_frame)
File “/home/openhabian/.local/lib/python3.10/site-packages/websocket/_core.py”, line 406, in recv_data_frame
frame = self.recv_frame()
File “/home/openhabian/.local/lib/python3.10/site-packages/websocket/_core.py”, line 445, in recv_frame
return self.frame_buffer.recv_frame()
File “/home/openhabian/.local/lib/python3.10/site-packages/websocket/_abnf.py”, line 338, in recv_frame
self.recv_header()
File “/home/openhabian/.local/lib/python3.10/site-packages/websocket/_abnf.py”, line 294, in recv_header
header = self.recv_strict(2)
File "/home/openhabian/.local/lib/python3.10/site-packages/websocket/abnf.py", line 373, in recv_strict
bytes = self.recv(min(16384, shortage))
File “/home/openhabian/.local/lib/python3.10/site-packages/websocket/_core.py”, line 529, in _recv
return recv(self.sock, bufsize)
File "/home/openhabian/.local/lib/python3.10/site-packages/websocket/socket.py", line 108, in recv
bytes = _recv()
File “/home/openhabian/.local/lib/python3.10/site-packages/websocket/_socket.py”, line 87, in _recv
return sock.recv(bufsize)
KeyboardInterrupt
Specifically, this happened after I ran getDeviceName(), then getBrandName, then getDiscovery.
I could then run getStorageSize(), getStorageUsed(), and getUptime(). If I stopped here, the script would end as expected.
but If I had anything after that (specifically individually tested were: getVersion(), getActivePattern(), getBrightnessSlider(), getColorControlNames(), getActiveControls())
However, getActiveVariables() worked.
If I didn’t have any of getStorageSIze(), getStorageUsed(), or getUptime(), then all the following requests worked.
I have updated my script, and it appears to be working to the best of my knowledge, with the problematic state requests commented out. I have included it below, for reference or others’ use. I based it on an old example of zranger1, and the transition function was suggested by (name not recalled, will update), otherwise the code is mine. It can be used/modified as desired. If you are looking to use it, you’re probably better off cutting out the nightlight, oasis, and sunrise functions, and likely further gutting it down to what you need. It could also benefit from error checking.
PBScript.py:
#!/usr/bin/env python3
"""
uses the pixelblaze-client library from, and based partially on the example scripy by JEM(ZRanger1)
Requires the pixelblaze-client version 1+, which also requires websocket-client, pytz and requests. If you get odd errors, you may benefit from uninstalling and re-installing (updated versions of ) those dependencies.
The pixelblaze-client requires Python 3.9+
Note, the functions for Oasis, sound, and sunrise depend on specific patterns being installed on your pixelblaze. Adapt to patterns specific to your installation.
in this example installation given its' integration with Openhab, located in /var/lib/openhab/PBScript.py
"""
#below line commented out as isntalled pixelblaze-client from zranger1's github
from pixelblaze import *
import sys
def listPB():
pbList = PixelblazeEnumerator()
print("Testing: PixelblazeEnumerator object created -- listening for Pixelblazes")
time.sleep(2)
print("Available Pixelblazes: ", pbList.getPixelblazeList())
def setOasis():
print("Setting pattern to Oasis")
# depreciated pb.stopSequencer() # make sure the sequencer isn't running
pb.setActivePatternByName('Oasis')
# pb.waitForEmptyQueue(1000)
print("setting color.")
setVar("aura",0.6666667)
#setColor(0.6666667)
#pb.setControl('aura', 0.66667, False) # ensure the colors are the default blues, as they are modified in some of my other scripts)
pb.setBrightnessSlider(1) # as often the lights will have been turned off, and Oasis is the default pattern for smart home toggling
print("done.")
def setSound():
print("Setting pattern to a sound pattern")
# depreciated pb.stopSequencer() # make sure the sequencer isn't running
pb.setActivePatternByName('sound - spectro kalidastrip')
# pb.waitForEmptyQueue(1000)
pb.setBrightnessSlider(1)
print("done")
def setSunrise():
print("Setting pattern to Sunrise pattern")
# depreciated pb.stopSequencer() # make sure the sequencer isn't running
pb.setActivePatternByName('Sunrise')
pb.setBrightnessSlider(1)
print("done")
def setNightlight():
print("Setting pattern to Nightlight")
# depreciated pb.stopSequencer() # make sure the sequencer isn't running
pb.setActivePatternByName('Nightlight')
pb.setBrightnessSlider(0.4)
print("done")
def setBrightness(brightness):
print("Setting brightness to ",brightness)
if (brightness > 1):
print("Maximum value should be 1.0. This value is too high. Scaling it by 100, to interpret it as a percent")
brightness = brightness/100
print("New brightness is: ",brightness)
pb.setBrightnessSlider(brightness)
print("done")
def ListPatterns():
print("Listing available patterns:")
result = pb.getPatternList(False)
for key, value in result.items():
print(key, ' : ', value,)
def ListVariables():
print("Available Variables: ",pb.getActiveVariables())
def setVar(varName, varValue):
print("attempting to set the variable: ")
print (varName)
# if pb.variableExists(varName):
pb.setActiveVariables({varName: varValue})
# else :
# print ("Variable does not exist: ")
# print (varName)
def setControl(controlName, controlValue):
print("attempting to set the control: ", controlName, "to: ")
print(controlValue)
print("Error checking is up to you!")
pb.setActiveControls({controlName: controlValue})
def setColor(color):
print("Attempting to set the HSV decimal color, should a designated color control exist. This function will need updating for an RGB picker")
print("If there is no designated color control, you could try listvariables/setvar or listcontrols/setcontrol to set the specific color variable/control")
colControl = pb.getColorControlName()
print("Color control : ", colControl)
pb.setColorControl(colControl,color)
def transitionBrightness(pb,level,seconds):
"""
Changes brightness on the Pixelblaze object <pb> to <level> over
<seconds> seconds. Note that this call will block execution for
the entire interval of the transition. It's a great candidate
for use w/the async library, (or for threading if you're really
old school.)
"""
# figure out how many requests we'll be sending and how quickly
maxRequestsPerSec = 5
waitInterval = 1 / maxRequestsPerSec;
steps = maxRequestsPerSec * seconds;
# get the current brightness
initialBrightness = pb.getBrightnessSlider()
# If levels are equal we're done. Take early out for
# performance
if (initialBrightness == level) :
return
# Do the fade out if we're going to a lower level
if (initialBrightness > level) :
i = steps
linearDelta = (initialBrightness - level) / steps
while (i > 0) :
newBrightness = level + ((linearDelta * i)) * pow(i/steps,3)
pb.setBrightnessSlider(newBrightness)
time.sleep(waitInterval)
i = i - 1
# Otherwise fade (new brightness is higher)
else :
i = 1
totalwait = 0;
linearDelta = (level - initialBrightness) / steps
while (i <= steps) :
newBrightness = initialBrightness + (((linearDelta * i)) * pow(i/steps,3))
pb.setBrightnessSlider(newBrightness)
time.sleep(waitInterval)
i = i + 1
def currentState():
print("Pixelblaze current state of device: ", pb.getDeviceName())
print("Brand name: ", pb.getBrandName())
print("Discovery Broadcast? : ", pb.getDiscovery())
# print("Storage size : ", pb.getStorageSize())
# print("Storage used : ", pb.getStorageUsed())
# print("Uptime : ", pb.getUptime()) # possibly results in a crash after this runs
print("Current firmware version : ", pb.getVersion()) #currently not working
print("Sequencer State : ", pb.getConfigSequencer())
patternList = pb.getPatternList()
patternId = pb.getActivePattern()
print("The current pattern ID: ", patternId)
print("The current pattern name: ", patternList[patternId])
print("The current brightness is: ", pb.getBrightnessSlider())
print("Available Variables: ",pb.getActiveVariables())
print("Available Colors: ",pb.getColorControlNames())
print("Available Controls: ",pb.getActiveControls())
argnum = len(sys.argv) - 1
# slot command line arguements into expected variables. Could likely benefit from error checking.
if (argnum < 1) :
ARG_ACTION = 'help'
ARG_IP='0.0.0.0'
ARG_Extra = 'none'
if (argnum == 1) :
ARG_ACTION = sys.argv[1]
ARG_IP='0.0.0.0'
ARG_Extra = 'none'
elif (argnum == 2) :
ARG_IP = sys.argv[1]
ARG_ACTION = sys.argv[2]
ARG_Extra = 'none'
elif (argnum == 3) :
ARG_IP = sys.argv[1]
ARG_ACTION = sys.argv[2]
ARG_Extra = sys.argv[3]
elif (argnum > 3 ) :
ARG_IP = sys.argv[1]
ARG_ACTION = sys.argv[2]
ARG_Extra = sys.argv[3]
ARG_FINAL = sys.argv[4]
# ARG_IP = sys.argv[1]
# ARG_ACTION = sys.argv[2]
#connect to pixelblaze, as long as there was an attempt at supplying an IP
if argnum > 1 :
pb = Pixelblaze(ARG_IP)
#start to process commands
if ARG_ACTION == 'fadein':
transitionBrightness(pb,1,3) #fades in to full brightness (1) over (3) seconds
elif ARG_ACTION == 'fadeout':
transitionBrightness(pb,0,3) #fades out to zero brightness (0) over (3) seconds
elif ARG_ACTION == 'on':
setBrightness(1)
elif ARG_ACTION == 'off':
setBrightness(0)
elif ARG_ACTION == 'list':
listPB()
elif ARG_ACTION == 'brightness':
newBrightness = float(ARG_Extra)
setBrightness(newBrightness)
elif ARG_ACTION == 'transition':
newBrightness = float(sys.argv[3])
transitionBrightness(pb,newBrightness,3)
elif ARG_ACTION == 'oasis':
setOasis()
elif ARG_ACTION == 'sunrise':
setSunrise()
elif ARG_ACTION == 'sound':
setSound()
elif ARG_ACTION == 'nightlight':
setNightlight()
elif ARG_ACTION == 'patternID':
pb = Pixelblaze(ARG_IP)
print("Attempting to set pattern by pattern ID to: ", ARG_Extra)
pb.setActivePattern(ARG_Extra)
elif ARG_ACTION == 'pattern':
pb = Pixelblaze(ARG_IP)
print("Attempting to set pattern to: ", ARG_Extra)
pb.setActivePatternByName(ARG_Extra)
#pb.close()
elif (ARG_ACTION == 'listvariables') or (ARG_ACTION == 'listvar'):
ListVariables()
elif ARG_ACTION == 'listpatterns':
ListPatterns()
elif ARG_ACTION == 'setvar' or (ARG_ACTION == 'setvariable'):
setVar(ARG_Extra, ARG_FINAL)
elif ARG_ACTION == 'setcontrol':
setControl(ARG_Extra, ARG_FINAL)
elif ARG_ACTION == 'color':
setColor(float(ARG_Extra))
elif ARG_ACTION == 'state':
currentState()
elif ARG_ACTION == 'none':
print("no command line arguments provided. exiting.")
elif (ARG_ACTION == 'help') or (ARG_ACTION == '-h') or (ARG_ACTION == '-help') or (ARG_ACTION == '--help') or (ARG_ACTION == '--h') :
print(" Usage: python3 PBScript.py IP_Address command(s)")
print("Specific commands: on, off, fadein, fadeout, transition <to brightness 0-1>, brightness <0-1>, listpatterns, listvariables, listcontrols, listcolors, setvar <variableName, variableValue>, setcontrol <controlName, controlValue>, pattern <new pattern name>, patternID <new pattern ID>, oasis, sound, sunrise, nightlight, state")
elif ARG_ACTION == 'listcontrols':
print("Available Controls: ",pb.getActiveControls())
elif ARG_ACTION == 'listcolors':
print("Available Colors: ",pb.getColorControlNames())
else:
print("Unrecognized Command")
edit: updated for pattern name in state function, as suggested by zranger1