Mercurial > code > home > repos > front-door-display
annotate web_to_mqtt.py @ 16:719c8cc4d8b2
electricity report
author | drewp@bigasterisk.com |
---|---|
date | Thu, 06 Jun 2024 17:52:46 -0700 |
parents | affb3c8f3f58 |
children |
rev | line source |
---|---|
4 | 1 import asyncio |
5 | 2 import itertools |
3 import random | |
4 import struct | |
4 | 5 import subprocess |
6 import tempfile | |
7 | |
8 import aiomqtt | |
9 from PIL import Image, ImageChops | |
10 | |
11 | |
12 class WebRenderer: | |
5 | 13 |
4 | 14 def __init__(self): |
5 | 15 self.chrome_proc = subprocess.Popen(["google-chrome", "--headless"]) |
4 | 16 print("Chrome subprocess started.") |
17 | |
5 | 18 async def capture_screenshot(self, url) -> Image.Image: |
19 out = tempfile.NamedTemporaryFile(suffix=".png", prefix='webrenderer_') | |
4 | 20 screenshot_command = [ |
21 "google-chrome", | |
22 "--headless", | |
11 | 23 "--window-size=480,320", |
4 | 24 f"--screenshot={out.name}", |
25 url, | |
26 ] | |
5 | 27 subprocess.run(screenshot_command, |
28 stdout=subprocess.DEVNULL, | |
29 stderr=subprocess.DEVNULL) | |
11 | 30 return Image.open(out.name).convert('RGB').rotate(-90, expand=True) |
4 | 31 |
32 | |
7
b46679798c51
mv esp code to this repo. still trying to get correct refreshes
drewp@bigasterisk.com
parents:
6
diff
changeset
|
33 blockX = 32 |
b46679798c51
mv esp code to this repo. still trying to get correct refreshes
drewp@bigasterisk.com
parents:
6
diff
changeset
|
34 blockY = 32 |
8
47795c3121f1
bufferless updates! mqtt message is sent over SPI and everything works
drewp@bigasterisk.com
parents:
7
diff
changeset
|
35 msgDelay = .05 |
5 | 36 dirtyQueue = {} |
4 | 37 |
38 | |
5 | 39 async def check_for_changes(renderer, client, last_image): |
40 current_image = await renderer.capture_screenshot( | |
41 "http://localhost:8002/front-door-display/scheduleLcd.html") | |
42 diff_image = ImageChops.difference(last_image, current_image) | |
6 | 43 for y in range(0, current_image.height, blockY): |
44 for x in range(0, current_image.width, blockX): | |
45 box = (x, y, x + blockX, y + blockY) | |
5 | 46 region = diff_image.crop(box) |
47 if region.getbbox(): | |
48 dirtyQueue[(x, y)] = current_image.crop(box) | |
49 await asyncio.sleep(0) | |
4 | 50 |
51 return current_image | |
52 | |
53 | |
5 | 54 async def sendDirty(client): |
55 while True: | |
56 if dirtyQueue: | |
57 # pos = random.choice(list(dirtyQueue.keys())) | |
8
47795c3121f1
bufferless updates! mqtt message is sent over SPI and everything works
drewp@bigasterisk.com
parents:
7
diff
changeset
|
58 pos = min(list(dirtyQueue.keys())) |
5 | 59 img = dirtyQueue.pop(pos) |
60 await tell_lcd(client, pos[0], pos[1], img) | |
7
b46679798c51
mv esp code to this repo. still trying to get correct refreshes
drewp@bigasterisk.com
parents:
6
diff
changeset
|
61 await asyncio.sleep(msgDelay) # too fast and esp restarts |
b46679798c51
mv esp code to this repo. still trying to get correct refreshes
drewp@bigasterisk.com
parents:
6
diff
changeset
|
62 |
5 | 63 |
64 framesSent = itertools.count() | |
65 | |
66 | |
67 async def tell_lcd(client: aiomqtt.Client, x: int, y: int, | |
68 region: Image.Image): | |
6 | 69 seq = next(framesSent) % 65535 |
7
b46679798c51
mv esp code to this repo. still trying to get correct refreshes
drewp@bigasterisk.com
parents:
6
diff
changeset
|
70 msg = struct.pack('HHHHH', seq, x, y, region.width, |
b46679798c51
mv esp code to this repo. still trying to get correct refreshes
drewp@bigasterisk.com
parents:
6
diff
changeset
|
71 region.height) + region.tobytes() |
b46679798c51
mv esp code to this repo. still trying to get correct refreshes
drewp@bigasterisk.com
parents:
6
diff
changeset
|
72 print(f'send {seq=} {x=} {y=} {region.width=} {region.height=} ', |
b46679798c51
mv esp code to this repo. still trying to get correct refreshes
drewp@bigasterisk.com
parents:
6
diff
changeset
|
73 end='\r', |
b46679798c51
mv esp code to this repo. still trying to get correct refreshes
drewp@bigasterisk.com
parents:
6
diff
changeset
|
74 flush=True) |
5 | 75 await client.publish('display/squib/updates', msg, qos=0) |
4 | 76 |
77 | |
78 async def main(): | |
5 | 79 # also listen for dirty msgs from the web page; see ts. |
80 # also get notified of new mqtt listeners who need a full image refresh. | |
4 | 81 renderer = WebRenderer() |
5 | 82 async with aiomqtt.Client("mqtt2") as client: |
83 asyncio.create_task(sendDirty(client)) | |
11 | 84 last_image = Image.new('RGB', (320,480)) |
4 | 85 while True: |
5 | 86 last_image = await check_for_changes(renderer, client, last_image) |
87 # we could get the web page to tell us when any dom changes | |
11 | 88 await asyncio.sleep(60) |
4 | 89 |
90 | |
91 if __name__ == "__main__": | |
92 asyncio.run(main()) |