Experimenting with an Insteon modem and RaspberryPi.
Status: I've been using this package to control a few lights since late 2017.
My old Insteon controller flaked out on me, so I've replaced it with a SmartHome PowerLinc serial modem (model #2413S) and a RaspberryPi. This project is the python code I'm using to communicate with the modem and to control things.
pip install PyDispatcher
pip install tzlocal
singleton.py is a simple implementation of the singleton design pattern copied from https://www.python.org/download/releases/2.2/descrintro/.
actions.py provides a cross-module initialization mechanism. The programmer identifies points in the lifecycle of the program that a module might want to perform some action at. Examples might include at program startup or shutdown, or startup or teardown of a particular service. A module can define functions with styleized names, e.g.
def _do_onStartup_logging(): logging.basicConfig(filename='modem.log', level=logging.INFO) global _logger _logger = logging.getLogger(__name__)
The main function of the application would call
actions.run('onStartup')to execute all "onStartup" actions defined in any imported module.
translator.py implements a (incomplete) model of the messages sent to and from the Insteon modem. It includes methods for translatiing between a human and program readable representation of a message to the list of bytes to communicate with the modem.
For example, the programatic representation of a command to turn on the devices in AllLink group 1 is
SendAllLinkCommand(LinkGroup(1), OnCmd(), Byte(0))
The byte representation of that command is
from translator import * cmd = SendAllLinkCommand(LinkGroup(1), OnCmd(), Byte(0)) cmd.encode() [2, 97, 1, 17, 0]
modem.py implements communication with the modem.
import modem from translator import * im = modem.InsteonModem("/dev/ttyUSB0") cmd = SendAllLinkCommand(LinkGroup(1), OnCmd(), Byte(0)) im.sendCommand(bytearray(cmd.encode())) rsp = im.readResponse() interpret_all(rsp, ReadFromModem)[0] [Echo(SendAllLinkCommand(StartByte(), AllLinkCmd(), LinkGroup(0x01), OnCmd(), Byte(0x00)), Ack())]
ReadFromModem is the subclass of Translator that serves as the superclass for all messages that could be read from the modem. In this case we just get the command we sent echoed back to us along with an Ack.
schedule.py implements scheduling of modem commands and other events.
For example, to turn on all Link group 1 devices at 7:00pm every day:
Event(InsteonCommandAction(im, SendAllLinkCommand(LinkGroup(1), OnCmd(), Byte(0))), DailyAt(19, 0)).schedule()
solar.py implements a not very accurate model for sunrise and sunset. It can also be used to schedule events:
sun = solar.Solar(myLatitude, myLongitude) Event(InsteonCommandAction(im, SendAllLinkCommand(LinkGroup(1), OnCmd(), Byte(0))), solar.SolarEvent(sun, 'sunset')).schedule()
The call
insteon_modem.read_link_db()
queries to identify all link groups.
The webserver module provides a very simple web interface on the specified port. It presents a page that lists the discovered link groups and allows for each group's devices to be sent an on or an off message.
import webserver webserver.run(port, insteon_modem)
import actions import insteon_logging import modem import pytz import solar import webserver from schedule import DailyAt, TimeOffset, Event, Scheduler im = modem.InsteonModem("/dev/ttyUSB0") sun = solar.Solar(latitude, longitude) im.read_link_db() # Schedule turning the devices in link group 4 on and off. Event(modem.InsteonCommandAction(im, SendAllLinkCommand(LinkGroup(4), OnCmd(), Byte(0))), # On 20 minutes before calculated sunset TimeOffset(-20, solar.SolarEvent(sun, 'sunset'))).schedule() Event(modem.InsteonCommandAction(im, SendAllLinkCommand(LinkGroup(4), OffCmd(), Byte(0))), # Off at 11pm. DailyAt(23, 0)).schedule() webserver.run(8000, im)
I run Raspbian on my Raspberry Pi. To start my home control scheduling and web services system when Raspbian comes up in multi-user mode, I add this line
(cd /home/pi/insteon_experiments; PYTHONPATH='/home/pi/.local/lib/python3.5/site-packages' /usr/bin/python3.5 /home/pi/insteon_experiments/main.py &) >/home/pi/insteon_experiments/STARTUP_LOG 2>&1
to /etc/rc.local.
-
http://www.madreporite.com/insteon/insteon.html provides a bunch of links to links and documentation.