# HG changeset patch # User drewp@bigasterisk.com # Date 1555835664 25200 # Node ID 139eee3a17c020f12620c929e269613251b462a1 # Parent 92d01aba812a62b99b3b3f33612d038ad8a6c582 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 diff -r 92d01aba812a -r 139eee3a17c0 service/garageArduino/bathroom_recv/bathroom_recv.ino --- 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 - -#include - -// 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(); -} - diff -r 92d01aba812a -r 139eee3a17c0 service/garageArduino/bathroom_satt/bathroom_satt.ino --- 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 -*/ - diff -r 92d01aba812a -r 139eee3a17c0 service/garageArduino/garage/garage.ino --- 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 - -/* -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> 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() diff -r 92d01aba812a -r 139eee3a17c0 service/garageArduino/index.html --- 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 @@ - - - - - garageArduino - - - - - -

garageArduino service

- -

Talking to an arduino uno on host slash

- -

Pulse pin 3 to trigger garage door opener

- -

PIR sensor (in a box) measuring front door motion:

- -

phototransistor watching IR pulses on the power meter: last pulse was ; current power usage is watts (assuming kwh/blink)

- -

Recent raw IR sensor data:

- -

- -

Bathroom LEDs

-
Send first color to all LEDs
-
-
-
-
- - - - - - - diff -r 92d01aba812a -r 139eee3a17c0 service/garageArduino/powermeter/analog-samples.png Binary file service/garageArduino/powermeter/analog-samples.png has changed diff -r 92d01aba812a -r 139eee3a17c0 service/garageArduino/powermeter/end-of-day.png Binary file service/garageArduino/powermeter/end-of-day.png has changed diff -r 92d01aba812a -r 139eee3a17c0 service/garageArduino/powermeter/sensor.sch --- 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 diff -r 92d01aba812a -r 139eee3a17c0 service/garageArduino/pydeps --- 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