changeset 492:139eee3a17c0

rm old arduino code for a few boards. includes driver for IR sensor taped to power meter; virtualwire communications from garage to bathroom. Ignore-this: de7e267e47243e122d0d8cc111d4497a
author drewp@bigasterisk.com
date Sun, 21 Apr 2019 01:34:24 -0700
parents 92d01aba812a
children f5664bea7cfe
files service/garageArduino/bathroom_recv/bathroom_recv.ino service/garageArduino/bathroom_satt/bathroom_satt.ino service/garageArduino/garage/garage.ino service/garageArduino/garageArduino.py service/garageArduino/index.html service/garageArduino/powermeter/analog-samples.png service/garageArduino/powermeter/end-of-day.png service/garageArduino/powermeter/sensor.sch service/garageArduino/pydeps
diffstat 9 files changed, 0 insertions(+), 834 deletions(-) [+]
line wrap: on
line diff
--- a/service/garageArduino/bathroom_recv/bathroom_recv.ino	Sun Apr 21 01:33:13 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
-  board: 'Digispark (Tiny Core)'
-  programmer: 'Digispark'
-  
-  pin 0 DI from radio
-  pin 1 DO to radio (and green status led)
-  pin 2 SCK to radio
-  pin 3 output to LED string
-  pin 4 input from garage arduino
-  pin 5 output to garage arduino
-    
-  (attiny85 pin 5 is MOSI, pin 6 is MISO, 7 might be clock)  
-  
-*/
-#include <VirtualWire.h>
-
-#include <Adafruit_NeoPixel.h>
-
-// Parameter 1 = number of pixels in strip
-// Parameter 2 = pin number (most are valid)
-// Parameter 3 = pixel type flags, add together as needed:
-//   NEO_RGB     Pixels are wired for RGB bitstream
-//   NEO_GRB     Pixels are wired for GRB bitstream
-//   NEO_KHZ400  400 KHz bitstream (e.g. FLORA pixels)
-//   NEO_KHZ800  800 KHz bitstream (e.g. High Density LED strip)
-Adafruit_NeoPixel strip = Adafruit_NeoPixel(4, 3, NEO_GRB + NEO_KHZ800);
-
-#define SET(i, r, g, b) strip.setPixelColor(i, strip.Color(r, g, b)); strip.show();
-
-int numLeds = 4;
-
-void wakeUpPattern() { 
-  for (int t = 0; t < 255; t += 2) {
-    for (int i = 0; i < numLeds; i++) {
-      //SET(i, 255 - t, max(0, 255 - t * 2), max(0, 255 - t * 3)); 
-      SET(i, 
-        (i % 2) ? (255 - t) : 0,
-        (i % 2) ? 0 : (255 - t),
-        (i % 2) ? (255 - t) : 0);
-    }
-    delay(10);
-  }
-  SET(0, 0, 0, 0);
-  SET(1, 0, 0, 0);
-  SET(2, 0, 0, 0);
-  SET(3, 0, 0, 0);
-}
-
-void blinkFailedMessageError() {
-  digitalWrite(1, 1);
-  delay(100);
-  digitalWrite(1, 0);
-}
-
-void blinkShortBufferError() {
-  digitalWrite(1, 1);
-  delay(100);
-  digitalWrite(1, 0);
-  delay(50);
-  digitalWrite(1, 1);
-  delay(100);
-  digitalWrite(1, 0);
-}
-
-void setup() {
-  pinMode(1, OUTPUT); // for errors
-  
-  vw_set_rx_pin(4);
-  vw_setup(2000);	 // Bits per sec
-
-  vw_rx_start();       // Start the receiver PLL running
-
-  strip.begin();
-  strip.show();
-
-  wakeUpPattern();
-}
-
-void loop() {
-  uint8_t buf[VW_MAX_MESSAGE_LEN];
-  uint8_t buflen = VW_MAX_MESSAGE_LEN;
-
-  vw_wait_rx();
-  int success = vw_get_message(buf, &buflen);
-  if (!success) {
-    blinkFailedMessageError();
-    return;
-  }
-  if (buflen < numLeds * 3) { 
-    blinkShortBufferError();
-    return;
-  }
-
-  for (int i=0; i < numLeds; i++) {
-    strip.setPixelColor(i, strip.Color(
-    buf[i * 3 + 0], 
-    buf[i * 3 + 1], 
-    buf[i * 3 + 2]));
-  }
-  strip.show();
-}
-
--- a/service/garageArduino/bathroom_satt/bathroom_satt.ino	Sun Apr 21 01:33:13 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-/*
-  - DI from radio
-  - DO to radio
-  - SCK to radio
-  - output to the LED string
-  - PIR in
-  - room light analog in
-  - temp/humid https://github.com/adafruit/DHT-sensor-library
-*/
-
--- a/service/garageArduino/garage/garage.ino	Sun Apr 21 01:33:13 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,188 +0,0 @@
-#include <VirtualWire.h>
-
-/*
-board is Arduino UNO with '328
- */
-
-int datapin  = 7; // DI
-int latchpin = 9; // LI
-int clockpin = 8; // CI
-
-unsigned long SB_CommandPacket;
-int SB_CommandMode;
-int SB_BlueCommand;
-int SB_RedCommand;
-int SB_GreenCommand;
-
-#define SHIFT(val) shiftOut(datapin, clockpin, MSBFIRST, val)
-
-void SB_SendPacket() {
-  /* high bits are 00 for color, 01 for current */
-   SB_CommandPacket = SB_CommandMode & B11;
-   SB_CommandPacket = (SB_CommandPacket << 10)  | (SB_BlueCommand & 1023);
-   SB_CommandPacket = (SB_CommandPacket << 10)  | (SB_RedCommand & 1023);
-   SB_CommandPacket = (SB_CommandPacket << 10)  | (SB_GreenCommand & 1023);
-
-   SHIFT(SB_CommandPacket >> 24);
-   SHIFT(SB_CommandPacket >> 16);
-   SHIFT(SB_CommandPacket >> 8);
-   SHIFT(SB_CommandPacket);
-}
-
-void latch() {
-   delayMicroseconds(100);
-   digitalWrite(latchpin,HIGH); // latch data into registers
-   delayMicroseconds(100);
-   digitalWrite(latchpin,LOW); 
-}
-
-void setCurrent(byte r, byte g, byte b) { 
- /* 127 = max */ 
-   SB_CommandMode = B01; // Write to current control registers
-   SB_RedCommand = r; 
-   SB_GreenCommand = g;
-   SB_BlueCommand = b;
-   SB_SendPacket();
-   latch();
-}
-
-
-void setup()   {                
-  
-  pinMode(2, INPUT);
-  digitalWrite(2, LOW); 
-// PIR sensor on here is a 
-// http://octopart.com/555-28027-parallax-708653 in a 
-// http://octopart.com/1551ggy-hammond-15686 box
-  
-  // the phototransistor on analog2 is jameco 2006414
-
-  pinMode(3, OUTPUT);
-  digitalWrite(3, LOW);
-  // this drives a relay for the garage door. There is a 
-  // LP filter on it so the garage doesn't open if there's 
-  // an arduino power-on glitch. It may be that atmel has 
-  // circuitry to prevent such glitches, so a pull-down
-  // resistor may be enough. I haven't checked carefully.
-
-  pinMode(4, OUTPUT);
-  pinMode(5, OUTPUT);
-  // video input selector. picks which video input will be multiplexed
-  // into the bt848 capture card
-
-  pinMode(6, OUTPUT);  // front yard light
-
-  pinMode(7, OUTPUT); // bathroom shiftbrite data
-  pinMode(8, OUTPUT); // bathroom shiftbrite clk
-  pinMode(9, OUTPUT); // bathroom shiftbrite latch
-  
-  vw_set_ptt_pin(11); // waste, but VW will be writing to this
-  vw_set_tx_pin(10); // bathroom new virtualwire out
-  
-  // Bits per sec. Match this in bathroom_recv. 
-  // The reason to have this anywhere high is to 
-  // make a color change block the sending arduino 
-  // for less time. 
-  // 2000bps -> 120ms PUT requests
-  // 8000bps -> 30ms PUT requests, but lots of message errors
-  vw_setup(2000); 
-  
-  for (int i=0; i < 1; i++) {
-    setCurrent(127, 127, 127);
-  }
-
-  Serial.begin(115200);
-}
-
-int newBlinks = 0;
-int lastLevel = 0;
-int threshold = 750;
-int hold = 3; // pulse must last this many loops. Guessing-- I don't know the loop rate or the pulse width
-int seenFor = 0;
-
-void loop()                     
-{
-  unsigned char head, cmd, arg;
-  int level = analogRead(3) < threshold;
-  
-  if (level) {
-     seenFor++; 
-     if (seenFor == hold) {
-        newBlinks++; 
-     }
-  } else {
-     seenFor = 0;
-  }
-
-  if (Serial.available() >= 3) {
-    head = Serial.read();
-    if (head != 0x60) {
-      Serial.flush();
-      return;
-    }
-    cmd = Serial.read();
-    arg = Serial.read();
-    Serial.flush();
-    if (cmd == 0x00) {
-      Serial.print("{\"ok\":true}\n");
-    } else if (cmd == 0x01) { // poll
-      Serial.print("{\"newBlinks\":");
-      Serial.print(newBlinks);
-      Serial.print(", \"motion\":");
-      Serial.print(digitalRead(2) ? "true" : "false");
-      Serial.print("}\n");
-      newBlinks = 0;
-    } else if (cmd == 0x02) {
-      // current level
-      Serial.print("{\"z\":");
-      Serial.print(analogRead(3));
-      Serial.print("}\n");
-    } else if (cmd == 0x03) {
-      if (arg != 0) {
-        threshold = arg << 2;
-      }
-      Serial.print("{\"threshold\":");
-      Serial.print(threshold);
-      Serial.print("}\n");
-    } else if (cmd == 0x04) {
-      digitalWrite(3, arg);
-      Serial.print("{\"garage\":");
-      Serial.print(arg ? "true" : "false");
-      Serial.print("}\n");     
-    } else if (cmd == 0x05) { // set video	
-      digitalWrite(4, arg & 1);
-      digitalWrite(5, arg & 2);
-      Serial.print("{\"videoSelect\":");
-      Serial.print(arg);
-      Serial.print("}\n");     
-    } else if (cmd == 0x06) { // talk to shiftbrite
-      /*
-        one byte for the string length, then a buffer to be shifted
-        out to all the shiftbrites
-      */
-      for (int i=0; i<arg; i++) {
-        while (Serial.available() == 0) NULL;
-        SHIFT(Serial.read());
-      }
-      latch();
-      Serial.print("{\"ok\":1}\n");
-    } else if (cmd == 0x07) { // send virtualwire
-       // arg is the number of bytes in the message to send
-      uint8_t msg[99];
-      for (int i=0; i<arg; i++) {
-        while (Serial.available() == 0) NULL;
-        msg[i] = Serial.read();
-      }
-      if (!vw_send(msg, arg)) {
-        Serial.print("{\"err\":\"message too long for virtualwire\"}");
-        return;
-      }
-      vw_wait_tx();
-      Serial.print("{\"sent\":");
-      Serial.print(arg);
-      Serial.print("}\n");
-    } 
-  }
-}
-
-	
--- a/service/garageArduino/garageArduino.py	Sun Apr 21 01:33:13 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,319 +0,0 @@
-#!bin/python
-"""
-talks to frontdoordriver.pde on an arduino
-"""
-
-from __future__ import division
-
-import cyclone.web, json, traceback, os, sys, time, logging, bitstring
-from twisted.internet import reactor, task, defer
-from twisted.web.client import getPage
-sys.path.append("/my/proj/house/frontdoor")
-from loggingserial import LoggingSerial        
-sys.path.append("/my/proj/homeauto/lib")
-from cycloneerr import PrettyErrorHandler
-from logsetup import log
-sys.path.append("../../../room")
-from carbondata import CarbonClient
-sys.path.append("/my/site/magma")
-from stategraph import StateGraph      
-from rdflib import Namespace, RDF, Literal
-from webcolors import hex_to_rgb, rgb_to_hex
-
-def rgbFromHex(h):
-    """returns tuple of 0..1023"""
-    norm = hex_to_rgb(h)
-    return tuple([x * 4 for x in norm])
-
-def hexFromRgb(rgb):
-    return rgb_to_hex(tuple([x // 4 for x in rgb]))
-
-
-ROOM = Namespace("http://projects.bigasterisk.com/room/")
-DEV = Namespace("http://projects.bigasterisk.com/device/")
-
-class ArduinoGarage(object):
-    def __init__(self, port='/dev/ttyACM0'):
-        self.ser = LoggingSerial(port=port, baudrate=115200, timeout=1)
-        time.sleep(2)  # wait for a arduino reset to pass
-        self.ser.flush()
-        self.ping()
-
-    def ping(self):
-        self.ser.write("\x60\x00\x00")
-        msg = self.ser.readJson()
-        assert msg == {"ok":True}, msg
-
-    def poll(self):
-        self.ser.write("\x60\x01\x00")
-        ret = self.ser.readJson()
-        return ret
-
-    def lastLevel(self):
-        self.ser.write("\x60\x02\x00")
-        return self.ser.readJson()['z']
-
-    def setThreshold(self, t):
-        """set 10-bit threshold"""
-        self.ser.write("\x60\x03"+chr(max(1 << 2, t) >> 2))
-        return self.ser.readJson()['threshold']
-
-    def setGarage(self, level):
-        """set garage door opener pin"""
-        self.ser.write("\x60\x04"+chr(int(bool(level))))
-        return self.ser.readJson()['garage']
-
-    def setVideoSelect(self, chan):
-        """set video select bits from 0..3"""
-        self.ser.write("\x60\x05"+chr(chan))
-
-        return self.ser.readJson()['videoSelect']
-
-    def shiftbrite(self, colors):
-        """
-        shift out this sequence of (r,g,b) triples of 10-bit ints
-        """
-        resetCurrent = "".join(bitstring.pack("0b01, uint:10, uint:10, uint:10",
-                                              127, 127, 127).bytes
-                               for loop in range(len(colors)))
-        out = "".join(bitstring.pack("0b00, uint:10, uint:10, uint:10",
-                                     b, r, g).bytes
-                      for r,g,b in colors)
-        out = resetCurrent + out
-        self.ser.write("\x60\x06" + chr(len(out)) + out)
-        msg = self.ser.readJson()
-        assert msg == {"ok":1}, msg
-
-    def virtualwire(self, colors):
-        """
-        send this sequence of (r,g,b) 8-bit triples
-        """
-        numLeds = 4
-        # vw receiver wants data for all leds every time
-        colors = (list(colors) + [(0,0,0)] * numLeds)[:numLeds]
-        msg = "".join("%s%s%s" % (chr(r), chr(g), chr(b)) for r,g,b in colors)
-        self.ser.write("\x60\x07" + chr(len(msg)) + msg)
-        msg = self.ser.readJson()
-        assert msg == {"sent": 12}, msg
-        
-
-class Index(PrettyErrorHandler, cyclone.web.RequestHandler):
-    def get(self):
-        """
-        this is an acceptable status check since it makes a round-trip
-        to the arduino before returning success
-        """
-        self.settings.arduino.ping()
-        
-        self.set_header("Content-Type", "application/xhtml+xml")
-        self.write(open("index.html").read())
-
-class GraphPage(PrettyErrorHandler, cyclone.web.RequestHandler):
-    def get(self):
-        self.set_header("Content-Type", "application/x-trig")
-        g = StateGraph(ROOM['garageArduino'])
-        self.settings.poller.assertIsCurrent()
-        g.add((DEV['frontDoorMotion'], ROOM['state'],
-               ROOM['motion'] if self.settings.poller.lastValues['motion'] else
-               ROOM['noMotion']))
-        g.add((ROOM['house'], ROOM['usingPower'],
-               Literal(self.settings.poller.lastWatts, datatype=ROOM["#watts"])))
-        self.write(g.asTrig())
-
-class FrontDoorMotion(PrettyErrorHandler, cyclone.web.RequestHandler):
-    def get(self):
-        self.set_header("Content-Type", "application/javascript")
-        self.settings.poller.assertIsCurrent()
-        self.write(json.dumps({"frontDoorMotion" :
-                               self.settings.poller.lastValues['motion']}))
-
-class HousePower(PrettyErrorHandler, cyclone.web.RequestHandler):
-    def get(self):
-        self.set_header("Content-Type", "application/javascript")
-        self.settings.poller.assertIsCurrent()
-        w = self.settings.poller
-        self.write(json.dumps({
-            "currentWatts" : round(w.lastWatts, 2) if isinstance(w.lastWatts, float) else w.lastWatts,
-            "lastPulseAgo" : "%.1f sec ago" % (time.time() - w.lastBlinkTime) if w.lastBlinkTime is not None else "unknown",
-            "kwhPerBlink" : w.kwhPerBlink}))
-
-class HousePowerRaw(PrettyErrorHandler, cyclone.web.RequestHandler):
-    """
-    raw data from the analog sensor, for plotting or picking a noise threshold
-    """
-    def get(self):
-        self.set_header("Content-Type", "application/javascript")
-        pts = []
-        for i in range(60):
-            level = self.settings.arduino.lastLevel()
-            pts.append((round(time.time(), 3), level))
-
-        self.write(json.dumps({"irLevels" : pts}))
-
-class HousePowerThreshold(PrettyErrorHandler, cyclone.web.RequestHandler):
-    """
-    the level that's between between an IR pulse and the noise
-    """
-    def get(self):
-        self.set_header("Content-Type", "application/javascript")
-        self.settings.poller.assertIsCurrent()
-        self.write(json.dumps({"threshold" : thr}))
-        
-    def put(self):
-        pass
-
-class GarageDoorOpen(PrettyErrorHandler, cyclone.web.RequestHandler):
-    def post(self):
-        self.set_header("Content-Type", "text/plain")
-        self.settings.arduino.setGarage(True)
-        self.write("pin high, waiting..\n")
-        self.flush()
-        d = defer.Deferred()
-        def finish():
-            self.settings.arduino.setGarage(False)            
-            self.write("pin low. Done")
-            d.callback(None)
-        reactor.callLater(1.5, finish) # this time depends on the LP circuit
-        return d
-
-class VideoSelect(PrettyErrorHandler, cyclone.web.RequestHandler):
-    def post(self): 
-        self.set_header("Content-Type", "application/javascript")
-        v = self.settings.arduino.setVideoSelect(int(self.request.body))
-        self.write(json.dumps({"videoSelect" : v}))
-
-class Brite(PrettyErrorHandler, cyclone.web.RequestHandler):
-    def get(self, chan):
-        self.set_header("Content-Type", "text/plain")
-        self.write(hexFromRgb(self.settings.colors[int(chan)]))
-        
-    def put(self, chan):
-        s = self.settings
-        s.colors[int(chan)] = rgbFromHex(self.request.body)
-        #s.arduino.shiftbrite(s.colors)
-        s.arduino.virtualwire([(r//4, g//4, b//4) for r,g,b in s.colors])
-    post = put
-
-class Application(cyclone.web.Application):
-    def __init__(self, ard, poller):
-        handlers = [
-            (r"/", Index),
-            (r"/graph", GraphPage),
-            (r"/frontDoorMotion", FrontDoorMotion),
-            (r'/housePower', HousePower),
-            (r'/housePower/raw', HousePowerRaw),
-            (r'/housePower/threshold', HousePowerThreshold),
-            (r'/garageDoorOpen', GarageDoorOpen),
-            (r'/videoSelect', VideoSelect), 
-            (r"/brite/(\d+)", Brite),
-        ]
-        colors = [(0,0,0)] * 4 # stored 10-bit for legacy (or future!) reasons
-        settings = {"arduino" : ard, "poller" : poller, "colors" : colors}
-        cyclone.web.Application.__init__(self, handlers, **settings)
-
-class Poller(object):
-    """
-    times the blinks to estimate power usage. Captures the other
-    returned sensor values too in self.lastValues
-    """
-    def __init__(self, ard, period):
-        self.ard = ard
-        self.period = period
-        self.carbon = CarbonClient(serverHost='bang')
-        self.lastBlinkTime = None
-        self.lastValues = None
-        self.lastPollTime = 0
-        self.lastWatts = "(just restarted; wait no data yet)"
-        self.kwhPerBlink = 1.0 # unsure
-        self.lastMotion = False
-
-    def assertIsCurrent(self):
-        """raise an error if the poll data is not fresh"""
-        dt = time.time() - self.lastPollTime
-        if dt > period * 2:
-            raise ValueError("last poll time was too old: %.1f sec ago" % dt)
-    
-    def poll(self):
-        now = time.time()
-        try:
-            try:
-                newData = ard.poll()
-            except ValueError, e:
-                print e
-                os.abort()
-            else:
-                self.lastPollTime = now
-                self.lastValues = newData # for other data besides the blinks
-                self.processBlinks(now, newData['newBlinks'])
-                self.processMotion(newData['motion'])
-            
-        except (IOError, OSError):
-            os.abort()
-        except Exception, e:
-            print "poll error", e
-            traceback.print_exc()
-
-    def processBlinks(self, now, b):
-        if b > 0:
-            if b > 1:
-                # todo: if it's like 1,1,2,2,2,2,1,1 then we
-                # need to subdivide those inner sample periods
-                # since there might really be two blinks. But
-                # if it's like 0,0,0,2,0,0, that should be
-                # treated like b=1 since it's probably noise
-                pass
-
-            if self.lastBlinkTime is not None:
-                dt = now - self.lastBlinkTime
-                dth = dt / 3600.
-                watts = self.kwhPerBlink / dth
-
-                if watts > 20000:
-                    # this pulse (or the previous one) is
-                    # likely noise. Too late for the previous
-                    # one, but we're going to skip this one
-                    return
-                else:
-                    self.lastWatts = watts
-
-                    # todo: remove this; a separate logger shall do it
-                    self.carbon.send('system.house.powerMeter_w', watts, now)
-
-            self.lastBlinkTime = now
-
-    def processMotion(self, state):
-        if state == self.lastMotion:
-            return
-        self.lastMotion = state
-        msg = json.dumps(dict(board='garage', 
-                              name="frontDoorMotion", state=state))
-        getPage('http://bang.bigasterisk.com:9069/inputChange',
-                method="POST",
-                postdata=msg,
-                headers={'Content-Type' : 'application/json'}
-                ).addErrback(self.reportError, msg)
-
-    def reportError(self, msg, *args):
-        print "post error", msg, args
-
-if __name__ == '__main__':
-
-    config = { # to be read from a file
-        'arduinoPort': '/dev/serial/by-id/usb-Arduino__www.arduino.cc__Arduino_Uno_6493534323335161A2F1-if00',
-        'servePort' : 9050,
-        'pollFrequency' : 5,
-        'boardName' : 'garage', # gets sent with updates
-        }
-
-    #from twisted.python import log as twlog
-    #twlog.startLogging(sys.stdout)
-
-    log.setLevel(logging.DEBUG)
-
-    ard = ArduinoGarage(port=config['arduinoPort'])
-
-    period = 1/config['pollFrequency']
-    p = Poller(ard, period)
-    task.LoopingCall(p.poll).start(period)
-    reactor.listenTCP(config['servePort'], Application(ard, p))
-    reactor.run()
--- a/service/garageArduino/index.html	Sun Apr 21 01:33:13 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
-"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-  <head>
-    <title>garageArduino</title>
-    <link rel="alternate" type="application/x-trig" title="RDF graph" href="graph" />
-    <style type="text/css" media="all">
-      /* <![CDATA[ */
-.val {
-font-weight: bold;
-} 
-.colorpicker {
-  display: inline-block;
-}
-/* ]]> */
-    </style>
-  </head>
-  <body>
-
-    <h1>garageArduino service</h1>
-
-    <p>Talking to an arduino uno on host <tt>slash</tt></p>
-
-    <p>Pulse pin 3 to trigger garage door opener <form method="post" action="garageDoorOpen"><input type="submit" value="Garage door opener"/></form></p>
-
-    <p><a href="http://octopart.com/555-28027-parallax-708653">PIR sensor</a> (in <a href="http://octopart.com/1551ggy-hammond-15686">a box</a>) measuring front door motion: <span class="val" id="frontDoorMotion"/></p>
-
-    <p><a href="http://www.jameco.com/webapp/wcs/stores/servlet/ProductDisplay?langId=-1&amp;productId=2006414&amp;catalogId=10001&amp;freeText=2006414&amp;app.products.maxperpage=15&amp;storeId=10001&amp;search_type=jamecoall&amp;ddkey=http:StoreCatalogDrillDownView">phototransistor</a> watching IR pulses on the power meter: last pulse was <span class="val" id="lastPulseAgo"/>; current power usage is <span class="val"><span id="currentWatts"/> watts</span> (assuming <span class="val" id="kwhPerBlink"/> kwh/blink)</p>
-
-    <p>Recent raw IR sensor data: <div><img src="" id="raw"/></div></p>
-
-    <p><button type="submit" id="refresh">refresh</button></p>
-
-    <p>Bathroom LEDs</p>
-    <div><input id="lockColor" type="checkbox"/> Send first color to all LEDs</div>
-    <div class="colorpicker" id="p0"></div>
-    <div class="colorpicker" id="p1"></div>
-    <div class="colorpicker" id="p2"></div>
-    <div class="colorpicker" id="p3"></div>
-
-    <script type="text/javascript" src="//bigasterisk.com/lib/jquery-2.0.3.min.js"/>
-    <script type="text/javascript" src="//bigasterisk.com/lib/farbtastic-1.2/farbtastic.js"></script>
-    <link rel="stylesheet" href="//bigasterisk.com/lib/farbtastic-1.2/farbtastic.css" type="text/css" />
-
-    <script type="text/javascript">
-     // <![CDATA[
-    $(function () {
-	function setTexts(data) {
-	  $.each(data, function (k,v) { $("#"+k).text(v); })
-	}
-	function refresh() {
-	    $.getJSON("frontDoorMotion", setTexts);
-	    $.getJSON("housePower", setTexts);
-
-	    $.getJSON("housePower/raw", function (data) {
-		var xp=[], yp=[];
-		var start = data.irLevels[0][0];
-		var maxTime = 0;
-		$.each(data.irLevels, function (i, xy) {
-		    maxTime = xy[0] - start;
-		    xp.push(maxTime.toPrecision(3));
-		    yp.push(xy[1]);
-		});
-		// edit with http://imagecharteditor.appspot.com/
-		$("#raw").attr("src",
-			       "http://chart.apis.google.com/chart"+
-			       "?chxr=0,0,"+maxTime+"|1,0,1024"+
-			       "&chds=0,"+maxTime+",0,1024"+
-			       "&chxl=2:|seconds"+
-                               "&chxs=0,676767,11.5,0,lt,676767|1,676767,11.5,-0.5,l,676767"+  
-			       "&chxt=x,y,x"+
-			       "&chs=600x200"+
-			       "&cht=lxy"+
-			       "&chco=76A4FB"+
-			       "&chd=t:"+xp.join(",")+"|"+yp.join(",")+
-			       "&chg=10,20"+
-			       "&chls=2"+
-			       "&chma=40,20,20,30"+
-			       "&chm=h,FF0000,0,0.7:50:2,1");
-	    });
-	}
-	refresh();
-	$("#refresh").click(refresh);
-
-        var inProgress = false;
-        var pending = {}; // url : data
-        function sendColor(url, newColor) {
-                inProgress = 1;
-                $.ajax({
-                    type: "put", url: url,
-                    contentType: "text/plain", data: newColor,
-                    success: function () {
-                      inProgress = false;
-                      $.each(pending, function (u, n) {
-                        delete pending[u];
-                        sendColor(u, n);
-                      });
-                    }
-                });
-        } 
-        function copyColor(newColor) {
-                   $.farbtastic("#p1").setColor(newColor);
-                   $.farbtastic("#p2").setColor(newColor);
-                   $.farbtastic("#p3").setColor(newColor);
-        }
-        $("#lockColor").click(function () { copyColor($.farbtastic("#p0").color); });
-        $.each([
-            ["#p0", "brite/0"],
-            ["#p1", "brite/1"],
-            ["#p2", "brite/2"],
-            ["#p3", "brite/3"],
-        ], function (i, row) {
-            var picker = $.farbtastic(row[0], function (newColor) {
-                if (row[1] == "brite/0" && $("#lockColor")[0].checked) {
-                   copyColor(newColor);
-                }
-                if (inProgress) {
-                  pending[row[1]] = newColor;
-                  return;
-                }
-                sendColor(row[1], newColor);
-            });
-            $.get(row[1], picker.setColor);
-        });
-
-    });
-     // ]]>
-    </script>
-  </body>
-</html>
Binary file service/garageArduino/powermeter/analog-samples.png has changed
Binary file service/garageArduino/powermeter/end-of-day.png has changed
--- a/service/garageArduino/powermeter/sensor.sch	Sun Apr 21 01:33:13 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-v 20100214 2
-C 40000 40000 0 0 0 title-B.sym
-C 44400 47000 1 0 0 photo-transistor-1.sym
-{
-T 44200 47500 5 6 0 1 0 0 1
-device=PS2501-1
-T 44660 47100 5 10 1 1 0 0 1
-refdes=Q?
-T 44360 47000 5 10 0 1 0 0 1
-device=photo-transistor
-}
-C 48000 48000 1 180 0 connector5-1.sym
-{
-T 46200 46500 5 10 0 0 180 0 1
-device=CONNECTOR_5
-T 47900 46300 5 10 1 1 180 0 1
-refdes=ARDUINO
-}
-N 44600 47000 44900 46900 4
-N 44900 46900 45900 46900 4
-N 44600 47400 46000 47400 4
-N 46000 47400 46300 47200 4
-C 46200 45600 1 0 0 ground.sym
-N 46400 45900 45900 46900 4
-C 50100 47300 1 180 0 terminal-1.sym
-{
-T 49790 46550 5 10 0 0 180 0 1
-device=terminal
-T 49790 46700 5 10 0 0 180 0 1
-footprint=CONNECTOR 1 1
-T 49850 47250 5 10 1 1 180 6 1
-refdes=~INPUT
-}
-N 49200 47200 47500 47200 4
-C 48800 47200 1 90 0 resistor-1.sym
-{
-T 48400 47500 5 10 0 0 90 0 1
-device=RESISTOR
-T 48500 47400 5 10 1 1 90 0 1
-refdes=20K
-}
-C 48500 48100 1 0 0 vcc-1.sym
-C 44400 49500 1 270 0 led-1.sym
-{
-T 45000 48700 5 10 0 0 270 0 1
-device=LED
-T 44800 48700 5 10 1 1 270 0 1
-refdes=LED?
-T 45200 48700 5 10 0 0 270 0 1
-symversion=0.1
-}
-N 44100 49500 48300 49500 4
-N 48300 48100 48300 49500 4
-N 48300 48100 48700 48100 4
-C 44500 48300 1 270 0 resistor-1.sym
-{
-T 44900 48000 5 10 0 0 270 0 1
-device=RESISTOR
-T 44800 48100 5 10 1 1 270 0 1
-refdes=150
-}
-N 44600 48600 44600 48300 4
-C 48700 45900 1 180 0 connector4-1.sym
-{
-T 46900 45000 5 10 0 0 180 0 1
-device=CONNECTOR_4
-T 48700 44500 5 10 1 1 180 0 1
-refdes=RJ11
-}
-N 47000 44800 44100 44800 4
-N 44100 44800 44100 49500 4
-N 47000 45100 45200 45100 4
-N 45200 45100 45200 47400 4
-N 46400 45900 47000 45900 4
-N 47000 45900 47000 45700 4
--- a/service/garageArduino/pydeps	Sun Apr 21 01:33:13 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-Twisted==12.1.0
-argparse==1.2.1
-bitstring==3.0.2
-cyclone==0.4
-isodate==0.4.8
-pyserial==2.6
-python-dateutil==2.1
-rdflib==3.2.1
-webcolors==1.4