-
Notifications
You must be signed in to change notification settings - Fork 0
/
x11-tasmota.py
executable file
·81 lines (67 loc) · 3.1 KB
/
x11-tasmota.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#!/usr/bin/python3
import json
import operator
import PIL.Image
import PIL.ImageStat
import time
import urllib.request
import Xlib.display
# FIXME: Config or cmdline switch this
sonoff_hostname = 'sonoff-6810'
# This function mostly copied from here: https://rosettacode.org/wiki/Color_of_a_screen_pixel#Python
o_x_display = Xlib.display.Display()
o_x_root = o_x_display.screen().root
o_x_geo = o_x_root.xinerama_get_screen_size(o_x_display.get_default_screen())
def get_x_image(): # noqa: E302
o_x_image = o_x_root.get_image(0, 0, o_x_geo.width, o_x_geo.height, Xlib.X.ZPixmap, 0xffffffff)
o_pil_image_rgb = PIL.Image.frombytes("RGB", (o_x_geo.width, o_x_geo.height), o_x_image.data, "raw", "BGRX")
return o_pil_image_rgb
# This function mostly copied from: https://zeevgilovitz.com/detecting-dominant-colours-in-python
def most_frequent_colour(image):
pixels = image.getcolors(o_x_geo.width * o_x_geo.height)
# Pixels is a list of tuples,
# the first item is the number of occurences,
# the 2nd item is the RGB of a particular colour.
#
# operator.itemgetter(0) is a more efficient alternative to:
# lambda i: i[0]
# Do I actually need a key at all though?
# I seem to get the same result with & without,
# but I don't know if that's the expected behaviour or just fluke
most_frequent_pixel = max(pixels, key=operator.itemgetter(0))
## This is dumb & inefficient
# most_frequent_pixel = pixels[0]
# for count, colour in pixels:
# if count > most_frequent_pixel[0]:
# most_frequent_pixel = (count, colour)
## I have no idea what this function was supposed to be, but everything works without it
# compare("Most Common", image, most_frequent_pixel[1])
return most_frequent_pixel
# Maybe give it just a little white so that the light is never really off?
# Keep this >0 so that the light never completely turns off
white = 0
def update_sonoff_colour(red, green, blue): # noqa: E302
# Make sure all the colours are at least 1,
# otherwise the light bulb will turn off and not come back on automatically
red = max(1, red)
green = max(1, green)
blue = max(1, blue)
# NOTE: Tasmota has been told not to power the globe on when setting the color via the SetOption20 config command
# NOTE: "Color2" = Set color adjusted to current Dimmer value.
# We don't actually want that though because that'd make 1,1,1 just be pure white.
req = urllib.request.Request(f"http://{sonoff_hostname}/cm",
data=f"cmnd=Color2 {red},{green},{blue},{white}".encode('ascii'))
return json.load(urllib.request.urlopen(req))
prev_colour = None
while True:
time.sleep(0.10)
_, colour = most_frequent_colour(get_x_image())
if colour != prev_colour:
prev_colour = colour
try:
print(update_sonoff_colour(*colour))
except urllib.request.http.client.RemoteDisconnected as e:
# "Remote end closed connection without response"
# Transient? Let's just try again and see what happens
print(e)
print(update_sonoff_colour(*colour))