diff --git a/.gitignore b/.gitignore index deb4fe6..40d3b35 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +config.py + # ---> Linux *~ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..98f8bb5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "report"] + path = report + url = https://git.mount-mockery.de/pylib/report.git diff --git a/__install__.py b/__install__.py new file mode 100644 index 0000000..3d93e4b --- /dev/null +++ b/__install__.py @@ -0,0 +1,41 @@ +#!/bin/python +# +import os +import sys + +SERVICE_FILE = """ +[Unit] +Description=Smarthome IR Remote Control +After=network-online.target +Wants=network-online.target +[Service] +User=%(UID)d +Group=%(GID)d +ExecStart=%(MY_PATH)s/remote_control.sh +Type=simple +[Install] +WantedBy=default.target +""" + + +def help(): + print("Usage: prog ") + +if __name__ == "__main__": + if len(sys.argv) == 4: + try: + uid = int(sys.argv[1]) + gid = int(sys.argv[2]) + except ValueError: + help() + else: + if os.path.isdir(sys.argv[3]): + with open(os.path.join(sys.argv[3], 'remote_control.service'), "w") as fh: + fh.write(SERVICE_FILE % { + "MY_PATH": os.path.dirname(os.path.abspath(__file__)), + "UID": uid, + "GID": gid}) + else: + help() + else: + help() diff --git a/config_example/config.py b/config_example/config.py new file mode 100644 index 0000000..eccfad0 --- /dev/null +++ b/config_example/config.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +import os +import report + +from remotes import yamaha_ras5 as amplifier +from remotes import technics_eur642100 as cd_player + +__BASEPATH__ = os.path.abspath(os.path.dirname(__file__)) + +MQTT_USER = "mqtt_username" +MQTT_PASS = "mqtt_password" +MQTT_SERVER = "mqtt_server" +MQTT_TOPIC = "mqtt_topic" + +SUPPORTED_REMOTES = { + amplifier.NAME: amplifier.ALL, + cd_player.NAME: cd_player.ALL +} + +# +# Logging +# +APP_NAME = "remote_control" +LOGTARGET = 'stdout' # possible choices are: 'logfile' or 'stdout' +LOGLVL = 'DEBUG' + +LOGHOST = 'cutelog' +LOGPORT = 19996 + +formatter = report.SHORT_FMT diff --git a/lirc/Technics-EUR642100.lircd.conf b/lirc/Technics-EUR642100.lircd.conf new file mode 100644 index 0000000..c64b76e --- /dev/null +++ b/lirc/Technics-EUR642100.lircd.conf @@ -0,0 +1,70 @@ +# +# This is a space encoded remote control from Technics +# +# lots of the codes are identical to the EUR643900 file. +# Probably this remote control does work with this file too +# (the power button is missing here). Major differences +# in the header are: eps, aeps, gap. +# +# contributed by Simon Budig +# +# brand: Technics +# model: EUR642100 (probably EUR643900 too) +# supported devices: SL-PG440A +# + +begin remote + + name EUR642100 + bits 16 + flags SPACE_ENC + eps 30 + aeps 100 + + header 3578 1674 + one 503 368 + zero 503 1238 + ptrail 503 + pre_data_bits 32 + pre_data 0xBFFBFAAF + gap 74826 + repeat_bit 0 + + begin codes + OPEN_CLOSE 0x0000000000007F2A + VOLDOWN 0x0000000000007B2E + VOLUP 0x000000000000FBAE + ONE 0x000000000000F7A2 + TWO 0x0000000000007722 + THREE 0x000000000000B7E2 + FOUR 0x0000000000003762 + FIVE 0x000000000000D782 + SIX 0x0000000000005702 + SEVEN 0x00000000000097C2 + EIGHT 0x0000000000001742 + NINE 0x000000000000E7B2 + ZERO 0x0000000000006732 + TEN 0x0000000000005E0B + TEN_PLUS 0x000000000000DE8B + PROGRAM 0x000000000000AEFB + CLEAR 0x000000000000FEAB + RECALL 0x0000000000007E2B + TIME_MODE 0x0000000000005500 + A_B_REPEAT 0x000000000000EDB8 + REPEAT 0x0000000000001D48 + RANDOM 0x0000000000004D18 + AUTO_CUE 0x0000000000002E7B + TAPE_LENGTH 0x0000000000002A7F + SIDE_A_B 0x000000000000CA9F + TIME_FADE 0x000000000000D683 + PEAK_SEARCH 0x0000000000000E5B + SEARCH_BACK 0x000000000000BFEA + SEARCH_FOR 0x0000000000003F6A + TRACK_NEXT 0x000000000000ADF8 + TRACK_PREV 0x0000000000006D38 + STOP 0x000000000000FFAA + PAUSE 0x0000000000009FCA + PLAY 0x000000000000AFFA + end codes + +end remote diff --git a/lirc/Yamaha-RAS5.lircd.conf b/lirc/Yamaha-RAS5.lircd.conf new file mode 100644 index 0000000..b6b9f7c --- /dev/null +++ b/lirc/Yamaha-RAS5.lircd.conf @@ -0,0 +1,54 @@ + +# Please take the time to finish this file as described in +# https://sourceforge.net/p/lirc-remotes/wiki/Checklist/ +# and make it available to others by sending it to +# +# +# This config file was automatically generated +# using lirc-0.10.1(default) on Sat Sep 3 23:03:52 2022 +# Command line used: --disable-namespace yamaha_ras5.conf +# Kernel version (uname -r): 5.15.61-v7+ +# +# Remote name (as of config file): Yamaha-RAS5 +# Brand of remote device, the thing you hold in your hand: +# Remote device model nr: +# Remote device info url: +# Does remote device has a bundled capture device e. g., a +# usb dongle? : +# For bundled USB devices: usb vendor id, product id +# and device string (use dmesg or lsusb): +# Type of device controlled +# (TV, VCR, Audio, DVD, Satellite, Cable, HTPC, ...) : +# Device(s) controlled by this remote: + +begin remote + + name RAS5 + bits 32 + flags SPACE_ENC|CONST_LENGTH + eps 30 + aeps 100 + + header 8921 4481 + one 536 1698 + zero 536 578 + ptrail 539 + repeat 8923 2258 + gap 107243 + toggle_bit_mask 0x0 + frequency 38000 + + begin codes + POWER 0x7E81542B 0x00000000 + PHONO 0x5EA12857 0x00000000 + DOCK 0xFE80522D 0x00000000 + CD 0x5EA1A8D7 0x00000000 + LINE1 0x5EA183FC 0x00000000 + LINE2 0x5EA11867 0x00000000 + LINE3 0x5EA198E7 0x00000000 + MUTE 0x5EA13847 0x00000000 + VOLUP 0x5EA15827 0x00000000 + VOLDOWN 0x5EA1D8A7 0x00000000 + end codes + +end remote diff --git a/remote_control.py b/remote_control.py new file mode 100644 index 0000000..4c84c0f --- /dev/null +++ b/remote_control.py @@ -0,0 +1,60 @@ +import config +import json +import lirc +import logging +import paho.mqtt.client as mqtt +import report +import socket +import time + +try: + from config import APP_NAME as ROOT_LOGGER_NAME +except ImportError: + ROOT_LOGGER_NAME = 'root' +logger = logging.getLogger(ROOT_LOGGER_NAME).getChild('main') + + +class remote_control(object): + def __init__(self): + self.__lirc_client__ = lirc.Client() + + self.__client__ = mqtt.Client(config.APP_NAME) # create client object + self.__client__.on_message = self.__receive__ # attach function to callback + self.__client__.username_pw_set(config.MQTT_USER, config.MQTT_PASS) # login with credentials + try: + self.__client__.connect(config.MQTT_SERVER, 1883) # establish connection + self.__client__.loop_start() # start the loop + for remote in config.SUPPORTED_REMOTES: + for command in config.SUPPORTED_REMOTES[remote]: + topic = config.MQTT_TOPIC + "/" + remote + "/" + command + logger.debug("Subscribing \"%s\"", topic) + self.__client__.subscribe(topic) # subscibe a topic + except (socket.timeout, OSError) as e: + logger.warning("Erro while setting up mqtt instance and listener") + + def __receive__(self, client, userdata, message): + try: + payload = json.loads(message.payload) + except json.decoder.JSONDecodeError: + payload = None + if payload is None: + remote = message.topic.split("/")[-2] + command = message.topic.split("/")[-1] + try: + self.__lirc_client__.send_once(remote, command) + except TimeoutError: + logger.exception("Timeout-Error while sending IR-Command.") + logger.info("Sending once: %s to %s.", command, remote) + elif payload is True: + logger.warning("Start of remote command NYI!") + elif payload is False: + logger.warning("Stop of remote command NYI!") + + +if __name__ == '__main__': + report.appLoggingConfigure(config.__BASEPATH__, config.LOGTARGET, ((config.APP_NAME, config.LOGLVL), ), fmt=config.formatter, host=config.LOGHOST, port=config.LOGPORT) + # + rc = remote_control() + # + while (True): + time.sleep(30) diff --git a/remote_control.sh b/remote_control.sh new file mode 100755 index 0000000..d2749d8 --- /dev/null +++ b/remote_control.sh @@ -0,0 +1,4 @@ +#!/bin/sh +# +BASEPATH=`dirname $0` +$BASEPATH/venv/bin/python $BASEPATH/remote_control.py \ No newline at end of file diff --git a/remotes/__init__.py b/remotes/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/remotes/technics_eur642100.py b/remotes/technics_eur642100.py new file mode 100644 index 0000000..1dc91e7 --- /dev/null +++ b/remotes/technics_eur642100.py @@ -0,0 +1,73 @@ +NAME = "EUR642100" +# +OPEN_CLOSE = "OPEN_CLOSE" +VOLDOWN = "VOLDOWN" +VOLUP = "VOLUP" +ONE = "ONE" +TWO = "TWO" +THREE = "THREE" +FOUR = "FOUR" +FIVE = "FIVE" +SIX = "SIX" +SEVEN = "SEVEN" +EIGHT = "EIGHT" +NINE = "NINE" +ZERO = "ZERO" +TEN = "TEN" +TEN_PLUS = "TEN_PLUS" +PROGRAM = "PROGRAM" +CLEAR = "CLEAR" +RECALL = "RECALL" +TIME_MODE = "TIME_MODE" +A_B_REPEAT = "A_B_REPEAT" +REPEAT = "REPEAT" +RANDOM = "RANDOM" +AUTO_CUE = "AUTO_CUE" +TAPE_LENGTH = "TAPE_LENGTH" +SIDE_A_B = "SIDE_A_B" +TIME_FADE = "TIME_FADE" +PEAK_SEARCH = "PEAK_SEARCH" +SEARCH_BACK = "SEARCH_BACK" +SEARCH_FOR = "SEARCH_FOR" +TRACK_NEXT = "TRACK_NEXT" +TRACK_PREV = "TRACK_PREV" +STOP = "STOP" +PAUSE = "PAUSE" +PLAY = "PLAY" +# +ALL = [ + OPEN_CLOSE, + VOLDOWN, + VOLUP, + ONE, + TWO, + THREE, + FOUR, + FIVE, + SIX, + SEVEN, + EIGHT, + NINE, + ZERO, + TEN, + TEN_PLUS, + PROGRAM, + CLEAR, + RECALL, + TIME_MODE, + A_B_REPEAT, + REPEAT, + RANDOM, + AUTO_CUE, + TAPE_LENGTH, + SIDE_A_B, + TIME_FADE, + PEAK_SEARCH, + SEARCH_BACK, + SEARCH_FOR, + TRACK_NEXT, + TRACK_PREV, + STOP, + PAUSE, + PLAY +] diff --git a/remotes/yamaha_ras5.py b/remotes/yamaha_ras5.py new file mode 100644 index 0000000..2fdd1d6 --- /dev/null +++ b/remotes/yamaha_ras5.py @@ -0,0 +1,25 @@ +NAME = "RAS5" +# +POWER = "POWER" +PHONO = "PHONO" +DOCK = "DOCK" +CD = "CD" +LINE1 = "LINE1" +LINE2 = "LINE2" +LINE3 = "LINE3" +MUTE = "MUTE" +VOLUP = "VOLUP" +VOLDOWN = "VOLDOWN" +# +ALL = [ + POWER, + PHONO, + DOCK, + CD, + LINE1, + LINE2, + LINE3, + MUTE, + VOLUP, + VOLDOWN +] \ No newline at end of file diff --git a/report b/report new file mode 160000 index 0000000..21bac82 --- /dev/null +++ b/report @@ -0,0 +1 @@ +Subproject commit 21bac82e0c459ebf6d34783c9249526a657a6bbd diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..6ebec75 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +paho-mqtt +lirc