changeset 773:bc3516d02762

old changes in espNode Ignore-this: cbdcaf859b465e76c2c98e0d4510a1d3
author drewp@bigasterisk.com
date Sun, 28 Jun 2020 14:05:12 -0700
parents 2500a3ee9102
children d05e2396ea5c
files espNode/air_quality_indoor.yaml espNode/air_quality_outdoor.yaml espNode/aircase.blend espNode/bed.yaml espNode/bed_bar_asher.yaml espNode/cabin.yaml espNode/caseback.stl espNode/casefront.stl espNode/esp8266_nightlight.yaml espNode/frontwindow.yaml espNode/garage_hall_cam.yaml espNode/garage_outside_cam.yaml espNode/nightlight_ari.yaml espNode/office_back_cam.yaml espNode/readcam.py espNode/sonoff_light.yaml espNode/tasks.py espNode/theater_blaster.yaml
diffstat 18 files changed, 745 insertions(+), 106 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/espNode/air_quality_indoor.yaml	Sun Jun 28 14:05:12 2020 -0700
@@ -0,0 +1,66 @@
+esphome:
+  name: air_quality_indoor
+  platform: ESP32
+  board: lolin32
+  build_path: build
+
+wifi:
+  ssid: !secret wifi_ssid
+  password: !secret wifi_password
+  domain: ''
+  use_address: 10.2.0.32
+  
+logger:
+  baud_rate: 115200
+  level: DEBUG
+  logs:
+    sensor: INFO
+    pmsx003: INFO
+    bme280.sensor: INFO
+    ccs811: INFO
+  
+ota:
+
+mqtt:
+  broker: '10.2.0.1'
+  port: 1883
+  username: ''
+  password: ''
+
+i2c:
+  sda: 21
+  scl: 22
+  scan: True
+  id: bus_a
+                                                       
+# GPIO13/RXD2 num 16 = pms tx (pin 5)
+# GPIO15/TXD2 num 17 = pms rx (pin 4)
+uart:
+  rx_pin: 16
+  baud_rate: 9600
+
+sensor:
+  - platform: bme280
+    temperature:
+      name: "BME280 Temperature"
+    pressure:
+      name: "BME280 Pressure"
+    humidity:
+      name: "BME280 Humidity"
+    address: 0x76
+    update_interval: 30s
+  - platform: ccs811
+    eco2:
+      name: "CCS811 eCO2 Value"
+    tvoc:
+      name: "CCS811 Total Volatile Organic Compound"
+    address: 0x5A
+    update_interval: 60s
+  - platform: pmsx003
+    type: PMSX003
+    pm_1_0:
+      name: "Particulate Matter <1.0µm Concentration"
+    pm_2_5:
+      name: "Particulate Matter <2.5µm Concentration"
+    pm_10_0:
+      name: "Particulate Matter <10.0µm Concentration"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/espNode/air_quality_outdoor.yaml	Sun Jun 28 14:05:12 2020 -0700
@@ -0,0 +1,66 @@
+esphome:
+  name: air_quality_outdoor
+  platform: ESP32
+  board: lolin32
+  build_path: build
+
+wifi:
+  ssid: !secret wifi_ssid
+  password: !secret wifi_password
+  domain: ''
+  use_address: 10.2.0.33
+  
+logger:
+  baud_rate: 115200
+  level: DEBUG
+  logs:
+    sensor: INFO
+    pmsx003: INFO
+    bme280.sensor: INFO
+    ccs811: INFO
+ 
+ota:
+
+mqtt:
+  broker: '10.2.0.1'
+  port: 1883
+  username: ''
+  password: ''
+
+i2c:
+  sda: 21
+  scl: 22
+  scan: True
+  id: bus_a
+                                                       
+# GPIO13/RXD2 num 16 = pms tx (pin 5)
+# GPIO15/TXD2 num 17 = pms rx (pin 4)
+uart:
+  rx_pin: 16
+  baud_rate: 9600
+
+sensor:
+  - platform: bme280
+    temperature:
+      name: "BME280 Temperature"
+    pressure:
+      name: "BME280 Pressure"
+    humidity:
+      name: "BME280 Humidity"
+    address: 0x76
+    update_interval: 30s
+  - platform: ccs811
+    eco2:
+      name: "CCS811 eCO2 Value"
+    tvoc:
+      name: "CCS811 Total Volatile Organic Compound"
+    address: 0x5A
+    update_interval: 60s
+  - platform: pmsx003
+    type: PMSX003
+    pm_1_0:
+      name: "Particulate Matter <1.0µm Concentration"
+    pm_2_5:
+      name: "Particulate Matter <2.5µm Concentration"
+    pm_10_0:
+      name: "Particulate Matter <10.0µm Concentration"
Binary file espNode/aircase.blend has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/espNode/bed.yaml	Sun Jun 28 14:05:12 2020 -0700
@@ -0,0 +1,89 @@
+# https://cdn.hackaday.io/files/269911154782944/Heltec_WIFI-LoRa-32_DiagramPinout.jpg
+
+esphome:
+  name: bed
+  platform: ESP32
+  board: lolin32
+  build_path: build
+
+wifi:
+  ssid: !secret wifi_ssid
+  password: !secret wifi_password
+  domain: ''
+  use_address: 10.2.0.90   # not stable!
+
+mqtt:
+  broker: '10.2.0.1'
+  port: 1883
+  username: ''
+  password: ''
+  
+logger:
+  baud_rate: 115200
+  level: DEBUG
+  
+ota:
+  
+#dallas:
+#  - pin: GPIO16
+#sensor:
+#  - platform: dallas
+#    index: 0
+#    name: temperature
+
+switch:
+  - {platform: gpio, pin: {mode: INPUT_PULLUP, number: 2, inverted: yes}, name: red_button}
+  - {platform: gpio, pin: {mode: INPUT_PULLUP, number: 15, inverted: yes}, name: green_button}
+  - {platform: gpio, pin: GPIO16, name: pir}
+  
+output:
+  - {platform: ledc, pin: GPIO19, id: headboard_w }
+  - {platform: ledc, pin: GPIO23, id: headboard_r }
+  - {platform: ledc, pin: GPIO18, id: headboard_g }
+  - {platform: ledc, pin: GPIO17, id: headboard_b }
+  
+light:
+  - platform: rgbw
+    name: headboard
+    red: headboard_r
+    green: headboard_g
+    blue: headboard_b
+    white: headboard_w
+
+    
+i2c:
+  sda: 4
+  scl: 15
+
+font:
+  - file: "/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf"
+    id: font_vera
+    size: 12
+    glyphs: "+-_.:0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz"
+
+text_sensor:
+  - platform: wifi_info
+    ip_address:
+      name: wifi_ip
+      id: wifi_ip
+    ssid:
+      name: wifi_ssid
+    bssid:
+      name: wifi_bssid
+
+sensor:
+  - platform: wifi_signal
+    id: my_wifi_signal
+    name: wifi_signal
+    update_interval: 4s
+    internal: true # no mqtt
+      
+display:
+  - platform: ssd1306_i2c
+    model: "SSD1306 128x64"
+    reset_pin: 16
+    address: 0x3C
+    lambda: |-
+      it.print(0, 0, id(font_vera), "bed 2: running");
+      it.printf(0, 20, id(font_vera), "wifi %s %.2f", id(wifi_ip).state.c_str(), id(my_wifi_signal).state);
+      
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/espNode/bed_bar_asher.yaml	Sun Jun 28 14:05:12 2020 -0700
@@ -0,0 +1,66 @@
+esphome:
+  name: bed_bar_asher
+  platform: esp8266
+  board: esp12e
+  build_path: build
+
+wifi:
+  ssid: !secret wifi_ssid
+  password: !secret wifi_password
+  domain: ''
+  use_address: 10.2.0.36
+  
+logger:
+  baud_rate: 115200
+  level: DEBUG
+  
+ota:
+
+mqtt:
+  broker: '10.2.0.1'
+  port: 1883
+  username: ''
+  password: ''
+
+light:
+  - platform: fastled_clockless
+    chipset: WS2812B
+    pin: GPIO14
+    num_leds: 38
+    rgb_order: GRB
+    name: "strip"
+    
+binary_sensor:
+  - platform: gpio
+    name: "button 1"
+    pin:
+      number: GPIO12
+      mode: INPUT_PULLUP
+      inverted: True
+    filters:
+      - delayed_off: 10ms
+  - platform: gpio
+    name: "button 2"
+    pin:
+      number: GPIO10
+      mode: INPUT_PULLUP
+      inverted: True
+    filters:
+      - delayed_off: 10ms
+  - platform: gpio
+    name: "button 3"
+    pin:
+      number: GPIO5
+      mode: INPUT_PULLUP
+      inverted: True
+    filters:
+      - delayed_off: 10ms
+  - platform: gpio
+    name: "button 4"
+    pin:
+      number: GPIO4
+      mode: INPUT_PULLUP
+      inverted: True
+    filters:
+      - delayed_off: 10ms
+ 
--- a/espNode/cabin.yaml	Sun Jun 28 14:03:10 2020 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-# https://cdn.hackaday.io/files/269911154782944/Heltec_WIFI-LoRa-32_DiagramPinout.jpg
-
-esphome:
-  name: cabin
-  platform: ESP32
-  board: lolin32
-  build_path: build
-  esphome_core_version: latest
-
-wifi:
-  ssid: !secret wifi_ssid
-  password: !secret wifi_password
-  domain: ''
-
-mqtt:
-  broker: '10.2.0.1'
-  port: 1883
-  username: ''
-  password: ''
-  
-logger:
-  baud_rate: 115200
-  level: DEBUG
-  
-ota:
-
-
-#dallas:
-#  - pin: GPIO16
-#sensor:
-#  - platform: dallas
-#    index: 0
-#    name: temperature
-
-light:
-  - platform: fastled_clockless
-    chipset: WS2812B
-    pin: GPIO21
-    num_leds: 16
-    rgb_order: GRB
-    name: "rgb"
-    
-i2c:
-  sda: 4
-  scl: 15
-
-font:
-  - file: "/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf"
-    id: font_vera
-    size: 14
-    
-display:
-  - platform: ssd1306_i2c
-    model: "SSD1306 128x64"
-    reset_pin: 16
-    address: 0x3C
-    lambda: |-
-      it.print(0, 0, id(font_vera), "cabin 1.0: running");
Binary file espNode/caseback.stl has changed
Binary file espNode/casefront.stl has changed
--- a/espNode/esp8266_nightlight.yaml	Sun Jun 28 14:03:10 2020 -0700
+++ b/espNode/esp8266_nightlight.yaml	Sun Jun 28 14:05:12 2020 -0700
@@ -8,7 +8,8 @@
 wifi:
   ssid: !secret wifi_ssid
   password: !secret wifi_password
-  domain: ''
+  use_address: ${wifi_addr}
+  domain: '.bigasterisk.com'
 
 mqtt:
   broker: '10.2.0.1'
@@ -18,6 +19,6 @@
   
 logger:
   baud_rate: 115200
-  level: DEBUG
+  level: INFO
   
 ota:
--- a/espNode/frontwindow.yaml	Sun Jun 28 14:03:10 2020 -0700
+++ b/espNode/frontwindow.yaml	Sun Jun 28 14:05:12 2020 -0700
@@ -1,7 +1,8 @@
 substitutions:
   location: display1
   board: d1_mini
-
+  wifi_addr: 10.2.0.97
+  
 <<: !include esp8266_nightlight.yaml
   
 i2c:
@@ -9,33 +10,67 @@
   scl: D5
 
 font:
-  - file: "/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf"
-    id: font_big
-    size: 24
-  - file: "/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf"
-    id: font_small
-    size: 12
+  - file: "Oswald-Regular.ttf"
+    id: font_20
+    size: 20
+    glyphs: ' .ASacdegiknorstuwDpCf'
+  - file: "Oswald-Regular.ttf"
+    id: font_13
+    size: 13
+    glyphs: 'CLOUcdeklnopsD. '
+  - file: "Oswald-Regular.ttf"
+    id: font_10
+    size: 10
+    glyphs: ' %0123456789.:NekortwDpnb-dB'
 
 text_sensor:
   - platform: mqtt_subscribe
-    name: "Data from topic"
-    id: bigtext
-    topic: frontwindow/bigtext
+    name: "line1"
+    id: line1
+    topic: frontwindow/line1
+    on_value:
+      then:
+        - component.update: my_display
+  - platform: mqtt_subscribe
+    name: "line2"
+    id: line2
+    topic: frontwindow/line2
+    on_value:
+      then:
+        - component.update: my_display
   - platform: mqtt_subscribe
-    name: "Data from topic"
-    id: smalltext
-    topic: frontwindow/smalltext
+    name: "line3"
+    id: line3
+    topic: frontwindow/line3
+    on_value:
+      then:
+        - component.update: my_display
+  - platform: mqtt_subscribe
+    name: "line4"
+    id: line4
+    topic: frontwindow/line4
+    on_value:
+      then:
+        - component.update: my_display
+
+sensor:
+  - platform: wifi_signal
+    name: "WiFi Signal Sensor"
+    update_interval: 10s
+    id: wifi_db
     
 display:
   - platform: ssd1306_i2c
+    id: my_display
     model: "SSD1306 128x64"
     address: 0x3c
     lambda: |-
       it.rectangle(0, 0, 127, 63);
-      it.printf(64, 5, id(font_big), TextAlign::TOP_CENTER, id(bigtext).state.c_str());
-      it.printf(64, 63-5, id(font_small), TextAlign::BOTTOM_CENTER, id(smalltext).state.c_str());
-      
-      
+      it.printf(64, 3, id(font_20), TextAlign::TOP_CENTER, id(line1).state.c_str());
+      it.printf(30, 28, id(font_13), TextAlign::TOP_CENTER, id(line2).state.c_str());
+      it.printf(103, 28, id(font_13), TextAlign::TOP_CENTER, id(line3).state.c_str());
+      it.printf(64, 63 - 5, id(font_10), TextAlign::BOTTOM_CENTER, "Network: %d dB", static_cast<int8_t>(id(wifi_db).state));
+
 spi:
   clk_pin: D4
   miso_pin: D1
@@ -48,5 +83,6 @@
     then:
       - mqtt.publish:
           topic: frontwindow/tag
+          retain: false
           payload: !lambda 'return x;'
       
--- a/espNode/garage_hall_cam.yaml	Sun Jun 28 14:03:10 2020 -0700
+++ b/espNode/garage_hall_cam.yaml	Sun Jun 28 14:05:12 2020 -0700
@@ -1,5 +1,8 @@
 # jump IO0 to GND on the board for programming
 
+# bang(pts/13):/my/proj/homeauto/espNode% forever { catchsegv ./readcam.py --cam garage_hall_cam  --port 10020 -v }
+
+
 esphome:
   name: garage_hall_cam
   platform: ESP32
@@ -10,7 +13,7 @@
   ssid: !secret wifi_ssid
   password: !secret wifi_password
   domain: ''
-  use_address: 10.2.0.21
+  use_address: 10.2.0.28
      
 #mqtt:
 #  broker: '10.2.0.1'
@@ -42,12 +45,30 @@
   power_down_pin: GPIO32
 
   name: camera
+
+  # https://github.com/esphome/esphome/blob/dev/esphome/components/esp32_camera/esp32_camera.cpp#L265 says a 'stream' is 5 sec long
+
   # setting to 5 causes 'Setup Failed: ERROR'
-  max_framerate: 1 fps
+  max_framerate: 4 fps
   # https://github.com/raphaelbs/esp32-cam-ai-thinker#capabilities says camera
   # is likely ov2640 with these native resolutions:
   # uxga=1600x1200 svga=800x600 cif=400x296
   # My camera has 'Setup Failed: ERROR' if this is not 640x480. Not sure why.
+  # Also the camera had 'Setup Failed: ERROR' when its cable needed reseating.
+
+  #   160x120 (QQVGA)    'Got invalid frame', then no more
+  #   128x160 (QQVGA2)
+  #   176x144 (QCIF)     fps: 25 jpg: 20 img: 2KB burst of frames then stopped. 
+  #                      fps: 20 jpg: 20 no frames
+  #   240x176 (HQVGA)
+  #   320x240 (QVGA)     fps: 10 jpg: 20 some frames, 4.5KB
+  #   400x296 (CIF)
+  #   640x480 (VGA)      fps: 4 jpg: 10 works,  20KB
+  #   800x600 (SVGA)
+  #   1024x768 (XGA)
+  #   1280x1024 (SXGA)   fps: 1  works
+  #   1600x1200 (UXGA)
+
   resolution: 640x480
   
   # 10 to 63. default=10. higher is
@@ -55,5 +76,5 @@
   # sets the lower limit to 10, but
   # https://github.com/raphaelbs/esp32-cam-ai-thinker/blob/master/components/ov2640/sensors/ov2640.c#L345
   # suggests that it might be 0 (for an ov2640, anyway).
-  jpeg_quality: 20
+  jpeg_quality: 10
   
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/espNode/garage_outside_cam.yaml	Sun Jun 28 14:05:12 2020 -0700
@@ -0,0 +1,97 @@
+# device is https://www.amazon.com/ESP32-CAM-Bluetooth-Camera-Module-Development/dp/B07S5PVZKV/ref=sr_1_3
+
+# has no rst pin, so 
+#  1. connect DTR to IO0
+#  2. inv monitor-usb --board office_back_cam
+#  3. press reset button
+#  4. ctrl-c,  inv program-board-over-usb --board office_back_cam
+
+# mosquitto_sub  -v -t office_back_cam/status
+
+# bang(pts/15):/my/proj/homeauto/espNode% catchsegv ./readcam.py --cam office_back_cam  --port 10021
+
+
+
+esphome:
+  name: garage_outside_cam
+  platform: ESP32
+  board: esp32cam
+  build_path: build
+
+wifi:
+  ssid: !secret wifi_ssid
+  password: !secret wifi_password
+  domain: ''
+  use_address: '10.2.0.44'
+
+mqtt:
+  broker: '10.2.0.1'
+  port: 1883
+  username: ''
+  password: ''
+  
+logger:
+  baud_rate: 115200
+  level: DEBUG
+  
+ota:
+
+api:
+  port: 6053
+  password: 'MyPassword'
+  
+# https://randomnerdtutorials.com/esp32-cam-ai-thinker-pinout/
+esp32_camera:
+  external_clock:
+    pin: GPIO0
+    frequency: 20MHz
+  i2c_pins:
+    sda: GPIO26
+    scl: GPIO27
+  data_pins: [GPIO5, GPIO18, GPIO19, GPIO21, GPIO36, GPIO39, GPIO34, GPIO35]
+  vsync_pin: GPIO25
+  href_pin: GPIO23
+  pixel_clock_pin: GPIO22
+  power_down_pin: GPIO32
+
+  name: camera
+
+  # https://github.com/esphome/esphome/blob/dev/esphome/components/esp32_camera/esp32_camera.cpp#L265 says a 'stream' is 5 sec long
+
+  # setting to 5 causes 'Setup Failed: ERROR'
+  max_framerate: 4 fps
+  # https://github.com/raphaelbs/esp32-cam-ai-thinker#capabilities says camera
+  # is likely ov2640 with these native resolutions:
+  # uxga=1600x1200 svga=800x600 cif=400x296
+  
+  #   160x120 (QQVGA)    'Got invalid frame', then no more
+  #   128x160 (QQVGA2)
+  #   176x144 (QCIF)     fps: 25 jpg: 20 img: 2KB burst of frames then stopped. 
+  #                      fps: 20 jpg: 20 no frames
+  #   240x176 (HQVGA)
+  #   320x240 (QVGA)     fps: 10 jpg: 20 some frames, 4.5KB
+  #   400x296 (CIF)
+  #   640x480 (VGA)      fps: 4 jpg: 10 works,  20KB
+  #   800x600 (SVGA)
+  #   1024x768 (XGA)
+  #   1280x1024 (SXGA)   fps: 1  works
+  #   1600x1200 (UXGA)
+
+  resolution: 640x480
+  
+  # 10 to 63. default=10. higher is
+  # worse. https://github.com/esphome/esphome/blob/6682c43dfaeb1c006943ae546145e5f22262cadb/esphome/components/esp32_camera/__init__.py#L84
+  # sets the lower limit to 10, but
+  # https://github.com/raphaelbs/esp32-cam-ai-thinker/blob/master/components/ov2640/sensors/ov2640.c#L345
+  # suggests that it might be 0 (for an ov2640, anyway).
+  jpeg_quality: 10
+ 
+output:
+  - platform: gpio
+    pin: GPIO4
+    id: gpio_4
+
+light:
+  - platform: binary
+    output: gpio_4
+    name: flash
--- a/espNode/nightlight_ari.yaml	Sun Jun 28 14:03:10 2020 -0700
+++ b/espNode/nightlight_ari.yaml	Sun Jun 28 14:05:12 2020 -0700
@@ -1,10 +1,32 @@
-substitutions:
-  location: ari
+esphome:
+  name: nightlight_ari
+  platform: esp8266
+  board: esp12e
+  build_path: build
+
+wifi:
+  ssid: !secret wifi_ssid
+  password: !secret wifi_password
+  use_address: 10.2.0.96
+#  domain: '.bigasterisk.com'
 
-<<: !include esp8266_nightlight.yaml
+mqtt:
+  broker: '10.2.0.1'
+  port: 1883
+  username: ''
+  password: ''
+  
+logger:
+  baud_rate: 115200
+  level: INFO
+  
+ota:
+
 
 dallas:
   - pin: GPIO5
+    update_interval: 10s
+
 sensor:
   - platform: dallas
     index: 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/espNode/office_back_cam.yaml	Sun Jun 28 14:05:12 2020 -0700
@@ -0,0 +1,122 @@
+# device is https://www.amazon.com/ESP32-CAM-Bluetooth-Camera-Module-Development/dp/B07S5PVZKV/ref=sr_1_3
+
+# has no rst pin, so 
+#  1. connect DTR to IO0
+#  2. inv monitor-usb --board office_back_cam
+#  3. press reset button
+#  4. ctrl-c,  inv program-board-over-usb --board office_back_cam
+
+# mosquitto_sub  -v -t office_back_cam/status
+
+# bang(pts/15):/my/proj/homeauto/espNode% catchsegv ./readcam.py --cam office_back_cam  --port 10021
+
+
+
+esphome:
+  name: office_back_cam
+  platform: ESP32
+  board: esp32cam
+  build_path: build
+
+wifi:
+  ssid: !secret wifi_ssid
+  password: !secret wifi_password
+  domain: ''
+  use_address: '10.2.0.35'
+
+mqtt:
+  broker: '10.2.0.1'
+  port: 1883
+  username: ''
+  password: ''
+  
+logger:
+  baud_rate: 115200
+  level: DEBUG
+  
+ota:
+
+api:
+  port: 6053
+  password: 'MyPassword'
+  
+# https://randomnerdtutorials.com/esp32-cam-ai-thinker-pinout/
+esp32_camera:
+  external_clock:
+    pin: GPIO0
+    frequency: 20MHz
+  i2c_pins:
+    sda: GPIO26
+    scl: GPIO27
+  data_pins: [GPIO5, GPIO18, GPIO19, GPIO21, GPIO36, GPIO39, GPIO34, GPIO35]
+  vsync_pin: GPIO25
+  href_pin: GPIO23
+  pixel_clock_pin: GPIO22
+  power_down_pin: GPIO32
+
+  name: camera
+
+  # https://github.com/esphome/esphome/blob/dev/esphome/components/esp32_camera/esp32_camera.cpp#L265 says a 'stream' is 5 sec long
+
+  # setting to 5 causes 'Setup Failed: ERROR'
+  max_framerate: 4 fps
+  # https://github.com/raphaelbs/esp32-cam-ai-thinker#capabilities says camera
+  # is likely ov2640 with these native resolutions:
+  # uxga=1600x1200 svga=800x600 cif=400x296
+  
+  #   160x120 (QQVGA)    'Got invalid frame', then no more
+  #   128x160 (QQVGA2)
+  #   176x144 (QCIF)     fps: 25 jpg: 20 img: 2KB burst of frames then stopped. 
+  #                      fps: 20 jpg: 20 no frames
+  #   240x176 (HQVGA)
+  #   320x240 (QVGA)     fps: 10 jpg: 20 some frames, 4.5KB
+  #   400x296 (CIF)
+  #   640x480 (VGA)      fps: 4 jpg: 10 works,  20KB
+  #   800x600 (SVGA)
+  #   1024x768 (XGA)
+  #   1280x1024 (SXGA)   fps: 1  works
+  #   1600x1200 (UXGA)
+
+  resolution: 640x480
+  
+  # 10 to 63. default=10. higher is
+  # worse. https://github.com/esphome/esphome/blob/6682c43dfaeb1c006943ae546145e5f22262cadb/esphome/components/esp32_camera/__init__.py#L84
+  # sets the lower limit to 10, but
+  # https://github.com/raphaelbs/esp32-cam-ai-thinker/blob/master/components/ov2640/sensors/ov2640.c#L345
+  # suggests that it might be 0 (for an ov2640, anyway).
+  jpeg_quality: 10
+ 
+output:
+  - platform: gpio
+    pin: GPIO4
+    id: gpio_4
+
+light:
+  - platform: fastled_clockless
+    chipset: WS2812B
+    pin: GPIO13
+    num_leds: 1
+    rgb_order: GRB
+    name: "strip"
+  # - platform: monochromatic
+  #   name: "flash"
+  #   output: flash_out
+  - platform: binary
+    output: gpio_4
+    name: flash
+
+  
+dallas:
+  - pin: GPIO15
+    update_interval: 10s
+
+sensor:
+  - platform: dallas
+    index: 0
+    name: temperature
+
+# output:
+#   - platform: ledc
+#     id: flash_out
+#     pin: GPIO4
+#     frequency: 19531Hz
--- a/espNode/readcam.py	Sun Jun 28 14:03:10 2020 -0700
+++ b/espNode/readcam.py	Sun Jun 28 14:05:12 2020 -0700
@@ -5,6 +5,9 @@
 import io
 import os
 import json
+from docopt import docopt
+from standardservice.logsetup import log, verboseLogging
+
 logging.basicConfig(level=logging.INFO)
 from aiohttp import web
 from aiohttp.web import Response
@@ -19,17 +22,34 @@
 import numpy
 
 class CameraReceiver:
-    def __init__(self, loop):
+    def __init__(self, loop, host):
         self.lastFrameTime = None
         self.loop = loop
+        self.host = host
         self.lastFrame = b"", ''
         self.recent = []
 
     async def start(self):
-        self.c = c = APIClient(self.loop, '10.2.0.21', 6053, 'MyPassword')
-        await c.connect(login=True)
-        await c.subscribe_states(on_state=self.on_state)
-        await c.request_image_stream()
+        try:
+            self.c = c = APIClient(self.loop, 
+            self.host,
+            6053, 'MyPassword')
+            await c.connect(login=True)
+            await c.subscribe_states(on_state=self.on_state)
+        except OSError:
+            loop.stop()
+            return
+        self.loop.create_task(self.start_requesting_image_stream_forever())
+
+    async def start_requesting_image_stream_forever(self):
+        while True:
+            try:
+                await self.c.request_image_stream()
+            except AttributeError:
+                self.loop.stop()
+                return
+            # https://github.com/esphome/esphome/blob/dev/esphome/components/esp32_camera/esp32_camera.cpp#L265 says a 'stream' is 5 sec long
+            await asyncio.sleep(4)
 
     def on_state(self, s):
         if isinstance(s, CameraState):
@@ -38,8 +58,8 @@
                 self.recent = self.recent[-10:]
 
             self.recent.append(jpg)
-            print('recent lens: %s' % (','.join(str(len(x))
-                                                for x in self.recent)))
+            #print('recent lens: %s' % (','.join(str(len(x))
+            #                                    for x in self.recent)))
         else:
             print('other on_state', s)
 
@@ -66,14 +86,8 @@
                 self.lastFrame = jpg, msg
                 self.lastFrameTime = time.time()
             else:
-                await asyncio.sleep(.5)
-
-loop = asyncio.get_event_loop()
+                await asyncio.sleep(.05)
 
-recv = CameraReceiver(loop)
-detector = apriltag.Detector()
-
-loop.create_task(recv.start())
 
 def imageUri(jpg):
     return 'data:image/jpeg;base64,' + binascii.b2a_base64(jpg).decode('ascii')
@@ -128,8 +142,35 @@
     """
     return Response(text=d, content_type='text/html')
 
+arguments = docopt('''
+this
 
+Usage:
+  this [-v] [--cam host] [--port to_serve]
+
+Options:
+  -v --verbose       more log
+  --port n           http server [default: 10020]
+  --cam host         hostname of esphome server
+''')
+
+verboseLogging(arguments['--verbose'])
+logging.getLogger('aioesphomeapi.connection').setLevel(logging.INFO)
+
+loop = asyncio.get_event_loop()
+
+recv = CameraReceiver(loop, arguments['--cam'])
+detector = apriltag.Detector()
+
+f = recv.start()
+loop.create_task(f)
+
+start_time = time.time()
 app = web.Application()
 app.router.add_route('GET', '/stream', stream)
 app.router.add_route('GET', '/', index)
-web.run_app(app, host='0.0.0.0', port=10020)
+try:
+    web.run_app(app, host='0.0.0.0', port=int(arguments['--port']))
+except RuntimeError as e:
+    log.error(e)
+log.info(f'run_app stopped after {time.time() - start_time} sec')
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/espNode/sonoff_light.yaml	Sun Jun 28 14:05:12 2020 -0700
@@ -0,0 +1,45 @@
+esphome:
+  name: sonoff_4
+  platform: esp8266
+  board: esp01_1m
+  build_path: build
+
+wifi:
+  ssid: !secret wifi_ssid
+  password: !secret wifi_password
+#  use_address: 10.2.0.96
+#  domain: '.bigasterisk.com'
+
+mqtt:
+  broker: '10.2.0.1'
+  port: 1883
+  username: ''
+  password: ''
+  
+logger:
+  baud_rate: 115200
+  level: INFO
+  
+ota:
+
+
+binary_sensor:
+  - platform: gpio
+    pin:
+      number: GPIO0
+      mode: INPUT_PULLUP
+      inverted: True
+    name: "Sonoff Basic Button"
+    on_press:
+      - switch.toggle: relay
+
+switch:
+  - platform: gpio
+    name: "Sonoff Basic Relay"
+    pin: GPIO12
+    id: relay
+
+status_led:
+  pin:
+    number: GPIO13
+    inverted: yes
--- a/espNode/tasks.py	Sun Jun 28 14:03:10 2020 -0700
+++ b/espNode/tasks.py	Sun Jun 28 14:05:12 2020 -0700
@@ -8,6 +8,8 @@
 
 @task
 def program_board_over_usb(ctx, board):
+    print('connect gnd, 3v3, rx/tx per https://randomnerdtutorials.com/esp32-cam-video-streaming-web-server-camera-home-assistant/, ')
+    print('rts to reset (if possible), dtr to gpio0 per https://github.com/espressif/esptool/wiki/ESP32-Boot-Mode-Selection#automatic-bootloader')
     ctx.run(f"docker run --rm -v `pwd`:/config -v /usr/share/fonts:/usr/share/fonts --device=/dev/ttyUSB0 -it {tag} {board}.yaml run", pty=True)
 
 @task
--- a/espNode/theater_blaster.yaml	Sun Jun 28 14:03:10 2020 -0700
+++ b/espNode/theater_blaster.yaml	Sun Jun 28 14:05:12 2020 -0700
@@ -2,7 +2,6 @@
   name: theater_blaster
   platform: esp32
   board: lolin32
-  build_path: build
 
 # MAC: 3c:71:bf:ab:6e:94
 
@@ -16,23 +15,30 @@
   port: 1883
   username: ''
   password: ''
-  on_message:
-    - topic: theater_blaster/ir_out
-      payload: "volume_up"
+  on_json_message:
+    - topic: theater_blaster/ir_out/volume_up
       then:
         - remote_transmitter.transmit_nec:
             address: 0x4BB6
             command: 0x40BF
             repeat:
-              times: 3
-    - topic: theater_blaster/ir_out
-      payload: "volume_down"
+              times: !lambda |-
+                if (x.containsKey("times")) {
+                  return x["times"];
+                }
+                return 1;
+    - topic: theater_blaster/ir_out/volume_down
       then:
         - remote_transmitter.transmit_nec:
             address: 0x4BB6
             command: 0xC03F
             repeat:
-              times: 3
+              times: !lambda |-
+                if (x.containsKey("times")) {
+                  return x["times"];
+                }
+                return 1;
+  on_message:
     - topic: theater_blaster/ir_out
       payload: "input_bd"
       then:
@@ -97,3 +103,20 @@
 #      address: 0x1234
 #      command: 0x78AB
       
+i2c:
+  sda: 4
+  scl: 15
+
+font:
+  - file: "/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf"
+    id: font_vera
+    size: 20
+    
+display:
+  - platform: ssd1306_i2c
+    model: "SSD1306 128x64"
+    reset_pin: 16
+    address: 0x3C
+    lambda: |-
+      it.print(128/2, 0+6, id(font_vera), TextAlign::TOP_CENTER, "big cast erisk");
+      it.print(128/2, 64-6, id(font_vera), TextAlign::BOTTOM_CENTER ,"Volume 45");