From 92adc6ea9b9bdd5ab8f29d134bf62f668a074f37 Mon Sep 17 00:00:00 2001 From: djerun Date: Mon, 29 Jul 2024 22:36:15 +0200 Subject: [PATCH 01/12] [hotfix] disable trap for photosensitive creatures --- animation.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/animation.py b/animation.py index 30e92fc..1fa4774 100644 --- a/animation.py +++ b/animation.py @@ -48,9 +48,9 @@ class RandomSingle(Animation): by Max & Lightmoll (https://lght.ml) from 2022-06-08 """ - def __init__(self, color): + def __init__(self, color, looptime=60): super().__init__() - self.PERIOD = 4 * 30 #frames + self.PERIOD = looptime * 30 #frames self.color = self._rand_color() self.last_colors = [] self.frame_counter = 0 @@ -92,10 +92,10 @@ class TwoColor(Steady): by Max & Lightmoll (https://lght.ml) from 2022-06-08 """ - def __init__(self, color): + def __init__(self, color, looptime=60): super().__init__(color) self.start_time = time() - self.PERIOD = 0.5 #s + self.PERIOD = looptime * 0.5 #s self.COL_1 = color #input color self.COL_2 = (255-self.r, 255-self.g, 255-self.b) #compl. color @@ -174,7 +174,7 @@ class Caramelldansen(Steady): class FadeTo(Steady): - def __init__(self, color, t=2.0): + def __init__(self, color, t=60.0): super(FadeTo, self).__init__(color) self.t = t self.start = time() @@ -192,7 +192,7 @@ class FadeTo(Steady): class RotatingRainbow(Animation): - def __init__(self, looptime=10.0): + def __init__(self, looptime=60.0): super(RotatingRainbow, self).__init__() self.looptime = looptime pass @@ -216,7 +216,7 @@ class RotatingRainbow(Animation): class Chase(Steady): - def __init__(self, color, looptime=1.0): + def __init__(self, color, looptime=60.0): super(Chase, self).__init__(color) self.looptime = looptime @@ -234,7 +234,7 @@ class Chase(Steady): class ChaseRandom(Animation): - def __init__(self, color, looptime=1.0): + def __init__(self, color, looptime=60.0): super(Chase, self).__init__(color) self.looptime = looptime @@ -256,4 +256,4 @@ def hsv_to_rgb(h, s, v): return [int(r * 255), int(g * 255), int(b * 255)] def rgb_to_hsv(r, g, b): - return colorsys.rgb_to_hsv(r/255,g/255,b/255) \ No newline at end of file + return colorsys.rgb_to_hsv(r/255,g/255,b/255) From d6cd834ca81944fa880983a7e272442db0f80765 Mon Sep 17 00:00:00 2001 From: Stefan Bethke Date: Sun, 11 Aug 2024 22:00:30 +0200 Subject: [PATCH 02/12] Remove super annoying effect Slow down rainbow Closes #3 --- animation.py | 2 +- views/index.tpl | 15 --------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/animation.py b/animation.py index 30e92fc..64f7fb0 100644 --- a/animation.py +++ b/animation.py @@ -192,7 +192,7 @@ class FadeTo(Steady): class RotatingRainbow(Animation): - def __init__(self, looptime=10.0): + def __init__(self, looptime=50.0): super(RotatingRainbow, self).__init__() self.looptime = looptime pass diff --git a/views/index.tpl b/views/index.tpl index 33624b2..580768b 100644 --- a/views/index.tpl +++ b/views/index.tpl @@ -17,25 +17,10 @@ -
- - -
-
- - -
- - -
-
- - -
Color From 93b409736f02b0d13a54f23e43abbecaa05cdf31 Mon Sep 17 00:00:00 2001 From: Stefan Bethke Date: Mon, 16 Dec 2024 16:15:56 +0100 Subject: [PATCH 03/12] Implement Hackertours effect --- animation.py | 32 ++++++++++++++++++++++++++++++-- dmx.py | 9 +++++++++ foobaz.py | 9 ++++++++- poetry.lock | 17 ++++++++--------- pyproject.toml | 1 + views/index.tpl | 4 ++++ 6 files changed, 60 insertions(+), 12 deletions(-) diff --git a/animation.py b/animation.py index 64f7fb0..28abb32 100644 --- a/animation.py +++ b/animation.py @@ -120,6 +120,7 @@ class TwoColor(Steady): def name(self): return str(self) + class Caramelldansen(Steady): """ by Max & Lightmoll (https://lght.ml) @@ -233,9 +234,36 @@ class Chase(Steady): return "chase" -class ChaseRandom(Animation): +class Hackertours(Steady): + """ + Base color yellow, with green wandering back and forth + """ + def __init__(self, color, base=(255,255,0), looptime=2.0): + super(Hackertours, self).__init__(color) + self.looptime = looptime + self.base = base + + def update(self, index, count): + # angle is the position of the highlight on a circle, range [0, 1] + angle = (time() / self.looptime + (index + 0.0) / count) % 1.0 + # map 0->1, 0.5->0, 1->1 to convert from circle to cylon + angle = abs(angle * 2 - 1) + l = 1 - min(abs(angle - 1 / count) * .9, 1.0 / count) * count + return ( + int(self.r * l + self.base[0] * (1-l)), + int(self.g * l + self.base[1] * (1-l)), + int(self.b * l + self.base[2] * (1-l))) + + def __str__(self): + return f"{type(self).__name__}({self.r}, {self.g}, {self.b}, {self.looptime:.2f})" + + def name(self): + return "hackertours" + + +class ChaseRandom(Steady): def __init__(self, color, looptime=1.0): - super(Chase, self).__init__(color) + super(ChaseRandom, self).__init__(color) self.looptime = looptime def update(self, index, count): diff --git a/dmx.py b/dmx.py index cc954de..e1c0410 100644 --- a/dmx.py +++ b/dmx.py @@ -47,6 +47,15 @@ class StairvilleLedPar56(RGB): dmx.set(self.slot + 6, 255) +class ZhennbyPar(RGB): + def __init__(self, dmx, slot=1): + super(ZhennbyPar, self).__init__(dmx, slot, 1) + dmx.set(self.slot + 0, 0) + dmx.set(self.slot + 4, 0) + dmx.set(self.slot + 5, 0) + dmx.set(self.slot + 6, 0) + + class DMX: def __init__(self, host, port=0x1936, universe=1, maxchan=512): self._host = host diff --git a/foobaz.py b/foobaz.py index 64f02d4..0db4db2 100644 --- a/foobaz.py +++ b/foobaz.py @@ -7,7 +7,7 @@ from typing import Tuple from bottle import post, request, route, run, static_file, view from animation import Off -from dmx import DMX, Bar252, StairvilleLedPar56, REDSpot18RGB +from dmx import DMX, Bar252, StairvilleLedPar56, REDSpot18RGB, ZhennbyPar room = '' @@ -74,6 +74,13 @@ def main(args): Bar252(dmx, 51), Bar252(dmx, 62), ] + elif args.room == "hackertours": + dmx._rgbs = [ + ZhennbyPar(dmx, 1), + ZhennbyPar(dmx, 8), + ZhennbyPar(dmx, 15), + ZhennbyPar(dmx, 22), + ] else: print(f"Unknown room {args.room}", file=sys.stderr) sys.exit(64) diff --git a/poetry.lock b/poetry.lock index 38d10b1..0fdf274 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,18 +1,17 @@ +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. + [[package]] name = "bottle" -version = "0.12.21" +version = "0.12.25" description = "Fast and simple WSGI-framework for small web-applications." -category = "main" optional = false python-versions = "*" +files = [ + {file = "bottle-0.12.25-py3-none-any.whl", hash = "sha256:d6f15f9d422670b7c073d63bd8d287b135388da187a0f3e3c19293626ce034ea"}, + {file = "bottle-0.12.25.tar.gz", hash = "sha256:e1a9c94970ae6d710b3fb4526294dfeb86f2cb4a81eff3a4b98dc40fb0e5e021"}, +] [metadata] -lock-version = "1.1" +lock-version = "2.0" python-versions = "^3.9" content-hash = "861e3ad9d0b00deb876d2ca7797a608f215c7b91ec9b38f367b24bd096a28478" - -[metadata.files] -bottle = [ - {file = "bottle-0.12.21-py3-none-any.whl", hash = "sha256:6e1c9817019dae3a8c20adacaf09035251798d2ae2fcc8ce43157ee72965f257"}, - {file = "bottle-0.12.21.tar.gz", hash = "sha256:787c61b6cc02b9c229bf2663011fac53dd8fc197f7f8ad2eeede29d888d7887e"}, -] diff --git a/pyproject.toml b/pyproject.toml index 038b5da..f33df46 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,6 +3,7 @@ name = "foobazdmx" version = "0.1.0" description = "" authors = ["Stefan Bethke "] +package-mode = false [tool.poetry.dependencies] python = "^3.9" diff --git a/views/index.tpl b/views/index.tpl index 580768b..1953385 100644 --- a/views/index.tpl +++ b/views/index.tpl @@ -21,6 +21,10 @@
+
+ + +
Color From 4b23f0a2bfee5768a89ac6c40fe9d4fef8413c6f Mon Sep 17 00:00:00 2001 From: Stefan Bethke Date: Mon, 16 Dec 2024 16:19:35 +0100 Subject: [PATCH 04/12] Not yet on Debian --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f33df46..01bb425 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ name = "foobazdmx" version = "0.1.0" description = "" authors = ["Stefan Bethke "] -package-mode = false +#package-mode = false [tool.poetry.dependencies] python = "^3.9" From b904e3514b67c2519a0a49739e3819719bf7ba26 Mon Sep 17 00:00:00 2001 From: Stefan Bethke Date: Mon, 16 Dec 2024 16:31:26 +0100 Subject: [PATCH 05/12] No dimming instead of full --- dmx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmx.py b/dmx.py index e1c0410..b34a850 100644 --- a/dmx.py +++ b/dmx.py @@ -50,7 +50,7 @@ class StairvilleLedPar56(RGB): class ZhennbyPar(RGB): def __init__(self, dmx, slot=1): super(ZhennbyPar, self).__init__(dmx, slot, 1) - dmx.set(self.slot + 0, 0) + dmx.set(self.slot + 0, 255) dmx.set(self.slot + 4, 0) dmx.set(self.slot + 5, 0) dmx.set(self.slot + 6, 0) From 60ffeefd6aec5e02e50dfa1c17362e1b15d2c11e Mon Sep 17 00:00:00 2001 From: Stefan Bethke Date: Mon, 16 Dec 2024 16:33:08 +0100 Subject: [PATCH 06/12] Add Hackertours to list of animations --- dmx.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dmx.py b/dmx.py index b34a850..d313f11 100644 --- a/dmx.py +++ b/dmx.py @@ -5,7 +5,8 @@ from threading import Thread from time import sleep from typing import Union -from animation import Animation, Off, RandomSingle, Steady, FadeTo, RotatingRainbow, Chase, TwoColor, Caramelldansen +from animation import Animation, Off, RandomSingle, Steady, FadeTo, RotatingRainbow, Chase, TwoColor, Caramelldansen, \ + Hackertours def ledlog(value): @@ -140,6 +141,8 @@ class DMX: animation = Caramelldansen(self._color) elif animation == "randomsingle": animation = RandomSingle(self._color) + elif animation == "hackertours": + animation = Hackertours(self._color) else: raise ValueError(f"No such animation {animation}") self._animation = animation From 10b89e784f192c9482a1a048dd4ed57c9f6041a9 Mon Sep 17 00:00:00 2001 From: Stefan Bethke Date: Mon, 16 Dec 2024 17:50:30 +0100 Subject: [PATCH 07/12] Rotation only for now --- animation.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/animation.py b/animation.py index 28abb32..0844503 100644 --- a/animation.py +++ b/animation.py @@ -238,7 +238,7 @@ class Hackertours(Steady): """ Base color yellow, with green wandering back and forth """ - def __init__(self, color, base=(255,255,0), looptime=2.0): + def __init__(self, color, base=(255,255,0), looptime=4.0): super(Hackertours, self).__init__(color) self.looptime = looptime self.base = base @@ -246,8 +246,6 @@ class Hackertours(Steady): def update(self, index, count): # angle is the position of the highlight on a circle, range [0, 1] angle = (time() / self.looptime + (index + 0.0) / count) % 1.0 - # map 0->1, 0.5->0, 1->1 to convert from circle to cylon - angle = abs(angle * 2 - 1) l = 1 - min(abs(angle - 1 / count) * .9, 1.0 / count) * count return ( int(self.r * l + self.base[0] * (1-l)), From 32bc2660d40cdc7f7153cbe49d7192afd4da9b5b Mon Sep 17 00:00:00 2001 From: Stefan Bethke Date: Tue, 17 Dec 2024 09:34:20 +0100 Subject: [PATCH 08/12] Make default background color into a warmer green --- animation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/animation.py b/animation.py index 0844503..86d5d23 100644 --- a/animation.py +++ b/animation.py @@ -238,7 +238,7 @@ class Hackertours(Steady): """ Base color yellow, with green wandering back and forth """ - def __init__(self, color, base=(255,255,0), looptime=4.0): + def __init__(self, color, base=(255,223,0), looptime=4.0): super(Hackertours, self).__init__(color) self.looptime = looptime self.base = base From 52c1cf5c11ebe1443d9b0e52109833ab406a8ccf Mon Sep 17 00:00:00 2001 From: Stefan Bethke Date: Tue, 17 Dec 2024 09:34:41 +0100 Subject: [PATCH 09/12] Allow initial animation and color to be set on the cmd line --- dmx.py | 2 +- foobaz.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dmx.py b/dmx.py index d313f11..453d116 100644 --- a/dmx.py +++ b/dmx.py @@ -165,5 +165,5 @@ class DMX: @color.setter def color(self, color): if self._color != color: - self._color = color + self._color = [int(c) for c in color] self.animation = self.animation diff --git a/foobaz.py b/foobaz.py index 0db4db2..7e0812b 100644 --- a/foobaz.py +++ b/foobaz.py @@ -51,6 +51,8 @@ def main(args): parser.add_argument('-l', '--listen', type=int, required=False, default=8080, help="TCP port to listen on for web") parser.add_argument('-r', '--room', type=str, required=True, help="light setup for room: shop or big") parser.add_argument('-u', '--universe', type=int, required=False, default=1, help="Universe to send to") + parser.add_argument('-A', '--animation', type=str, required=False, default="off", help="Initial animation") + parser.add_argument('-C', '--color', type=str, required=False, default="255,255,0", help="Initial color") args = parser.parse_args(args) print(f"Starting DMX via Art-Net to {args.artnet}", file=sys.stderr) @@ -86,8 +88,8 @@ def main(args): sys.exit(64) room = args.room dmx.animation = Off() - dmx.color = (0, 0, 0) - dmx.animation = "off" + dmx.color = args.color.split(',') + dmx.animation = args.animation run(host='0.0.0.0', port=args.listen, reloader=False, debug=True) From 104333b1f5fce3bedb60a101f6420b3d53a3e63f Mon Sep 17 00:00:00 2001 From: Stefan Bethke Date: Tue, 17 Dec 2024 09:42:45 +0100 Subject: [PATCH 10/12] Add a use unit for hackertours --- hackertours.unit | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 hackertours.unit diff --git a/hackertours.unit b/hackertours.unit new file mode 100644 index 0000000..b986db1 --- /dev/null +++ b/hackertours.unit @@ -0,0 +1,10 @@ +[Unit] +Description=Run foobazdmx controller in Hackertours config + +[Service] +Type=simple +ExecStart=poetry python ./foobaz.py -a 127.0.0.1 -r hackertours -A hackertours -C 0,255,32 +WorkingDirectory=~/working/foobazdmx + +[Install] +WantedBy=default.target From 77cea0bcc06681ae77682f3fc1a4b3e99b361013 Mon Sep 17 00:00:00 2001 From: Stefan Bethke Date: Tue, 17 Dec 2024 10:16:32 +0100 Subject: [PATCH 11/12] Correct syntax and name --- hackertours.service | 13 +++++++++++++ hackertours.unit | 10 ---------- 2 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 hackertours.service delete mode 100644 hackertours.unit diff --git a/hackertours.service b/hackertours.service new file mode 100644 index 0000000..8c4d774 --- /dev/null +++ b/hackertours.service @@ -0,0 +1,13 @@ +[Unit] +Description=Run foobazdmx controller in Hackertours config + +[Service] +Type=simple +ExecStart=poetry run python ./foobaz.py -a 127.0.0.1 -r hackertours -A hackertours -C 0,255,32 +WorkingDirectory=%h/working/foobazdmx +Restart=on-failure + +[Install] +WantedBy=default.target + +# link or copy me to ~/.config/systemd/user diff --git a/hackertours.unit b/hackertours.unit deleted file mode 100644 index b986db1..0000000 --- a/hackertours.unit +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=Run foobazdmx controller in Hackertours config - -[Service] -Type=simple -ExecStart=poetry python ./foobaz.py -a 127.0.0.1 -r hackertours -A hackertours -C 0,255,32 -WorkingDirectory=~/working/foobazdmx - -[Install] -WantedBy=default.target From ef3c8d9a2c52c13c8c00b46257f80f8b06cfc1f6 Mon Sep 17 00:00:00 2001 From: Stefan Bethke Date: Mon, 23 Dec 2024 10:40:23 -0500 Subject: [PATCH 12/12] Add Entec RGBW --- dmx.py | 15 ++++++++++++--- foobaz.py | 6 ++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/dmx.py b/dmx.py index 453d116..e01d8f4 100644 --- a/dmx.py +++ b/dmx.py @@ -21,9 +21,13 @@ class RGB: def rgb(self, color): (r, g, b) = color - self.dmx.set(self.slot + self.offset + 0, ledlog(r)) - self.dmx.set(self.slot + self.offset + 1, ledlog(g)) - self.dmx.set(self.slot + self.offset + 2, ledlog(b)) + try: + self.dmx.set(self.slot + self.offset + 0, ledlog(r)) + self.dmx.set(self.slot + self.offset + 1, ledlog(g)) + self.dmx.set(self.slot + self.offset + 2, ledlog(b)) + except Exception as e: + print(f'slot={self.slot}, offset={self.offset}') + raise(e) class Bar252(RGB): @@ -57,6 +61,11 @@ class ZhennbyPar(RGB): dmx.set(self.slot + 6, 0) +class Entec6RGBW(RGB): + def __init__(self, dmx, slot=1): + super(Entec6RGBW, self).__init__(dmx, slot) + + class DMX: def __init__(self, host, port=0x1936, universe=1, maxchan=512): self._host = host diff --git a/foobaz.py b/foobaz.py index 7e0812b..b1b5d01 100644 --- a/foobaz.py +++ b/foobaz.py @@ -7,7 +7,7 @@ from typing import Tuple from bottle import post, request, route, run, static_file, view from animation import Off -from dmx import DMX, Bar252, StairvilleLedPar56, REDSpot18RGB, ZhennbyPar +from dmx import DMX, Bar252, StairvilleLedPar56, REDSpot18RGB, ZhennbyPar, Entec6RGBW room = '' @@ -56,7 +56,7 @@ def main(args): args = parser.parse_args(args) print(f"Starting DMX via Art-Net to {args.artnet}", file=sys.stderr) - dmx = DMX(args.artnet, maxchan=128, universe=args.universe) + dmx = DMX(args.artnet, maxchan=512, universe=args.universe) if args.room == "shop": dmx._rgbs = [ @@ -83,6 +83,8 @@ def main(args): ZhennbyPar(dmx, 15), ZhennbyPar(dmx, 22), ] + elif args.room == "defrag": + dmx._rgbs = [Entec6RGBW(dmx, 300 + i*4) for i in range(19)] else: print(f"Unknown room {args.room}", file=sys.stderr) sys.exit(64)