changeset 491:6b153374b871

start this python bridge between a monome and lightsd
author Louis Opter <kalessin@kalessin.fr>
date Sun, 04 Sep 2016 22:42:09 -0700
parents b5efb1c879c6
children 6fce645a848a
files add_monolight.patch series
diffstat 2 files changed, 182 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/add_monolight.patch	Sun Sep 04 22:42:09 2016 -0700
@@ -0,0 +1,181 @@
+# HG changeset patch
+# Parent  4734caf1ac9fbbb1cad0363e207b9b065db1fb57
+Start a script to control bulbs through a Monome
+
+diff --git a/.hgignore b/.hgignore
+--- a/.hgignore
++++ b/.hgignore
+@@ -2,3 +2,4 @@
+ .*\.py[co]$
+ ^build
+ ^pcaps
++.*\.egg-info$
+diff --git a/monolight/monolight/__init__.py b/monolight/monolight/__init__.py
+new file mode 100644
+diff --git a/monolight/monolight/cli.py b/monolight/monolight/cli.py
+new file mode 100644
+--- /dev/null
++++ b/monolight/monolight/cli.py
+@@ -0,0 +1,85 @@
++import asyncio
++import click
++import locale
++import monome
++import os
++import subprocess
++import random
++
++ENCODING = locale.getpreferredencoding()
++
++
++FADERS_MAX_VALUE = 100
++
++
++class Faders(monome.Monome):
++    def __init__(self):
++        super().__init__('/faders')
++
++    def ready(self):
++        self.led_all(0)
++        self.led_row(0, self.height - 1, [1] * self.width)
++
++        self.row_values = []
++        row_value = 0
++        for i in range(self.height):
++            self.row_values.append(int(round(row_value)))
++            row_value += FADERS_MAX_VALUE / (self.height - 1)
++
++        self.values = [random.randint(0, FADERS_MAX_VALUE) for f in range(self.width)]
++        self.faders = [asyncio.async(self.fade_to(f, 0)) for f in range(self.width)]
++
++    def grid_key(self, x, y, s):
++        if s == 1:
++            self.faders[x].cancel()
++            self.faders[x] = asyncio.async(self.fade_to(x, self.row_to_value(y)))
++
++    def value_to_row(self, value):
++        return sorted([
++            i for i in range(self.height)],
++            key=lambda i: abs(self.row_values[i] - value)
++        )[0]
++
++    def row_to_value(self, row):
++        return self.row_values[self.height - 1 - row]
++
++    @asyncio.coroutine
++    def fade_to(self, x, new_value):
++        while self.values[x] != new_value:
++            if self.values[x] < new_value:
++                self.values[x] += 1
++            else:
++                self.values[x] -= 1
++            col = [0 if c > self.value_to_row(self.values[x]) else 1 for c in range(self.height)]
++            col.reverse()
++            self.led_col(x, 0, col)
++            yield from asyncio.sleep(1/100)
++
++
++def get_lightsd_rundir():
++    try:
++        lightsdrundir = subprocess.check_output(["lightsd", "--rundir"])
++    except Exception as ex:
++        click.echo(
++            "Couldn't infer lightsd's runtime directory, is lightsd installed? "
++            "({})\nTrying build/socket…".format(ex),
++            err=True
++        )
++        lightscdir = os.path.realpath(__file__).split(os.path.sep)[:-2]
++        lightsdrundir = os.path.join(*[os.path.sep] + lightscdir + ["build"])
++    else:
++        lightsdrundir = lightsdrundir.decode(ENCODING).strip()
++
++    return lightsdrundir
++
++LIGHTSD_SOCKET = "unix://" + os.path.join(get_lightsd_rundir(), "socket")
++
++
++@click.command()
++@click.option("--serialoscd-host", default="127.0.0.1")
++@click.option("--serialoscd-port", type=click.IntRange(0, 2**16 - 1))
++@click.option("--lightsd-url", default=LIGHTSD_SOCKET)
++def main(serialoscd_host, serialoscd_port, lightsd_url):
++    loop = asyncio.get_event_loop()
++    asyncio.async(monome.create_serialosc_connection(Faders), loop=loop)
++    loop.run_forever()
+diff --git a/monolight/monolight/lightsc.py b/monolight/monolight/lightsc.py
+new file mode 100644
+--- /dev/null
++++ b/monolight/monolight/lightsc.py
+@@ -0,0 +1,16 @@
++# Copyright (c) 2016, Louis Opter <louis@opter.org>
++#
++# This file is part of lighstd.
++#
++# lighstd is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# lighstd is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with lighstd.  If not, see <http://www.gnu.org/licenses/>.
+diff --git a/monolight/setup.py b/monolight/setup.py
+new file mode 100644
+--- /dev/null
++++ b/monolight/setup.py
+@@ -0,0 +1,51 @@
++# Copyright (c) 2016, Louis Opter <louis@opter.org>
++#
++# This file is part of lighstd.
++#
++# lighstd is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# lighstd is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with lighstd.  If not, see <http://www.gnu.org/licenses/>.
++
++import setuptools
++
++version = "0.0.1.dev0"
++
++setuptools.setup(
++    name="monolight",
++    version=version,
++    description="A Monome UI to control smart bulbs using lightsd",
++    author="Louis Opter",
++    author_email="louis@opter.org",
++    packages=setuptools.find_packages(exclude=['tests', 'tests.*']),
++    include_package_data=True,
++    entry_points={
++        "console_scripts": [
++            "monolight = monolight.cli:main",
++        ],
++    },
++    install_requires=[
++        "click~=6.6",
++        "pymonome~=0.8.2",
++    ],
++    tests_require=[
++        "doubles~=1.1.3",
++        "freezegun~=0.3.5",
++        "pytest~=3.0",
++    ],
++    extras_require={
++        "dev": [
++            "flake8",
++            "pdbpp",
++            "pep8",
++        ],
++    },
++)
--- a/series	Sat Jul 16 18:31:18 2016 -0700
+++ b/series	Sun Sep 04 22:42:09 2016 -0700
@@ -1,4 +1,5 @@
 ask_for_remote_dest_before_running_hg_out.patch
+add_monolight.patch
 docker_images.patch
 add_power_transition.patch
 open_gateway_on_any_bulb_response.patch #+future