Skip to content

Instantly share code, notes, and snippets.

@wsoyka wsoyka/yeelight-cli.py
Last active Jul 15, 2019

Embed
What would you like to do?
yeelight python cli script
import argparse
import struct
import time
from yeelight import Bulb
##################################################################################
##################################################################################
## Easily run actions on your Yeelights ##
## (e.g. when your Home Automation solution doesn't properly support Yeelights) ##
## This script is based on: https://gitlab.com/stavros/python-yeelight/ ##
## Thanks to stavros for building the interface to the yeelights! ##
## To use you first have to install the plugin via pip3 install yeelight ##
##################################################################################
##################################################################################
"""
TODO
support multiple bulbs
expose duration of change
"""
#####################################################################
# If you want to extend this script: most arg keys are only set in #
# ordered_args, irgnore the mirrored ones, they are not set. #
#####################################################################
# get order of args to run in actions in order, kudos to
# https://stackoverflow.com/a/9028031 and
# https://stackoverflow.com/a/8632404
def make_custom_action(customval):
class CustomAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
if not 'ordered_args' in namespace:
setattr(namespace, 'ordered_args', [])
previous = namespace.ordered_args
# decide if we want passed args or set custom ones
if (customval is 'use_passed'):
previous.append((self.dest, values))
else:
previous.append((self.dest, customval))
setattr(namespace, 'ordered_args', previous)
if hasattr(namespace, self.dest):
delattr(namespace, self.dest)
return CustomAction
parser = argparse.ArgumentParser(
description='Control Yeelights with CLI arguments.\nBased on https://gitlab.com/stavros/python-yeelight.\n' +
'Commands order will be recognized and the same command can be executed multiple times in one run.',
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('--address', '-a', dest="addr", default='10.0.0.66', metavar='XXX.XXX.XXX.XXX',
help="IP adress of Yeelight (HAS TO BE IN DEVELOPMENT/LAN MODE!)")
parser.add_argument('--delay', '-d', dest="delay", type=float, default=0.25,
help="delay between each command in seconds. setting to 0 can and probably will lead do commands "
+ "not being recognized by lamp")
parser.add_argument('--on', '-on', dest="on",
action=make_custom_action(True), nargs=0, help="turn lamp on")
parser.add_argument('--off', '-off', dest="on",
action=make_custom_action(False), nargs=0, help="turn lamp off")
parser.add_argument('--toggle', dest="toggle",
action=make_custom_action(None), nargs=0, help="toggle lamp")
parser.add_argument('--restart', '-re', dest="restart", action=make_custom_action(None), nargs=0,
help="toggle lamp twice")
parser.add_argument('--brightness', '-bright', dest="bright", type=float, metavar="PERCENT",
action=make_custom_action('use_passed'), nargs='?', help="set brightness to 0-100")
parser.add_argument('--color-temperature', '-ct', dest="ct", type=int, action=make_custom_action('use_passed'),
nargs='?', metavar="KELVIN", help="set color temperature of lamp")
parser.add_argument('--hue-color-temperature', '-hct', dest="hct", type=int, action=make_custom_action('use_passed'),
nargs='?', metavar="HUECT",
help="set color temperature of Yeelight based on color temperature of Phillips Hue light "
+"(different than normal color temperature!)")
parser.add_argument('--hex-color', '-hc', dest="hc", type=str, action=make_custom_action('use_passed'), nargs='?',
metavar="FFFFFF", help="set color of lamp based on hex")
# parser.add_argument('--red', '-r', dest="red", type=int, metavar="RED")
# parser.add_argument('--green', '-g', nargs='?',dest="green", type=int, metavar="GREEN")
# parser.add_argument('--blue', '-b', nargs='?', dest="blue", type=int, metavar="BLUE")
args = parser.parse_args()
def check_rgb(r, g, b):
return 0 <= r <= 255 and 0 <= g <= 255 and 0 <= b <= 255
# check if any of the given values where set
def any_set(list):
for i in list:
if i is not None:
return True
return False
def hue_ct_to_ct(huect):
return 1000000 / huect
def on(bool):
if bool:
print("turning lamp on")
bulb.turn_on()
else:
print("turning lamp off")
bulb.turn_off()
def toggle():
print("toggle")
bulb.toggle()
def restart():
bulb.toggle()
time.sleep(0.25)
bulb.toggle()
def bright(b):
if 0 <= b <= 100:
print("set bright to: {0}".format(b))
bulb.set_brightness(b)
else:
print("bright has to be between 0 and 100")
# make this hex based for simpler parsing
"""#if args.red is not None or args.blue is not None or args.green is not None:
def rgb(red,green,blue):
if check_rgb(red, green, blue):
print("set rgb to: {0},{1},{2}".format(red,green,blue))
bulb.set_rgb(red, blue, green)
else:
# if any_set([args.red, args.green, args.blue]):
parser.error('"All 3 RGB channels have to be set.')
"""
def ct(color_temp):
print("set color temperature to: {0}".format(color_temp))
bulb.set_color_temp(color_temp)
def hct(hue_color_temp):
new_ct = hue_ct_to_ct(hue_color_temp)
print("setting ct from huect: {0}".format(new_ct))
bulb.set_color_temp(new_ct)
def hc(hex_color):
red, green, blue = struct.unpack('BBB', bytes.fromhex(hex_color))
print("setting color to rgb: ({0},{1},{2}) (hex: {3})".format(
red, green, blue, hex_color))
bulb.set_rgb(red, blue, green)
# Set HSV value.
# bulb.set_hsv(153, 100, 50)
# Set hue and saturation, but keep value (brightness) the same.
# bulb.set_hsv(320, 100)
# Save this setting as default.
# bulb.set_default()
if hasattr(args, 'ordered_args'):
print(args)
# discard original args as they are all unset
orig_args = args # keep a backup
# now use ordered args as main args
args = args.ordered_args
bulb = Bulb(orig_args.addr, effect="smooth", duration=1000)
# interpret variables as method names to not have huge if else tree
for method_name, value in args:
# print("key {0} value {1}".format(method_name,value))
# find method by str name
possibles = globals().copy()
possibles.update(locals())
method = possibles.get(method_name)
# print(method)
if not method:
print("couldnt find function: {0}".format(method))
if value is None:
method()
else:
method(value)
time.sleep(orig_args.delay)
else:
parser.error("Specify at least one arg")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.