]> hydra-www.ietfng.org Git - acmetensortoys-snakecontrol/commitdiff
Minor overhaul for LCD and BME
authorNathaniel Wesley Filardo <nwfilardo@gmail.com>
Sun, 7 May 2017 19:38:20 +0000 (15:38 -0400)
committerNathaniel Wesley Filardo <nwfilardo@gmail.com>
Sun, 7 May 2017 19:38:20 +0000 (15:38 -0400)
Add BME280 sensor to tank top
Add lcdproc interface which scrapes pidmonitor logs for display
Other tweaks around town

bin/BME280.py [new file with mode: 0644]
bin/lcdproc.expect [new file with mode: 0755]
bin/monitor-log-cgi.sh
bin/monitor.py [deleted file]
bin/pidloop.py
bin/pidmonitor.py
bin/rrdtool-creates.sh
data/.gitignore
runit/pi-sc-lcd/run [new file with mode: 0755]
runit/pi-sc-monitor/log/run
runit/pi-sc-monitor/run

diff --git a/bin/BME280.py b/bin/BME280.py
new file mode 100644 (file)
index 0000000..7abcecf
--- /dev/null
@@ -0,0 +1,213 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015 Andrey Koryagin
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import smbus
+import time
+
+# BME280 default address.
+BME280_I2CADDR           = 0x76
+
+# BME280 Registers
+BME280_CONTROL_MEAS      = 0xF4
+BME280_CONTROL_HUM       = 0xF2
+
+BME280_CONFIG            = 0xF5
+BME280_PRESSURE          = 0xF7
+BME280_TEMP              = 0xFA
+BME280_HUMIDITY          = 0xFD
+
+BME280_DIG_T1            = 0x88
+BME280_DIG_T2            = 0x8A
+BME280_DIG_T3            = 0x8C
+BME280_DIG_P1            = 0x8E
+BME280_DIG_P2            = 0x90
+BME280_DIG_P3            = 0x92
+BME280_DIG_P4            = 0x94
+BME280_DIG_P5            = 0x96
+BME280_DIG_P6            = 0x98
+BME280_DIG_P7            = 0x9A
+BME280_DIG_P8            = 0x9C
+BME280_DIG_P9            = 0x9E
+BME280_DIG_H1            = 0xA1
+BME280_DIG_H2            = 0xE1
+BME280_DIG_H3            = 0xE3
+BME280_DIG_H4            = 0xE4
+BME280_DIG_H5            = 0xE5
+BME280_DIG_H6            = 0xE7
+
+# Oversampling Setting
+BME280_OVERS_T1          = 0x20
+BME280_OVERS_T2          = 0x40
+BME280_OVERS_T4          = 0x60
+BME280_OVERS_T8          = 0x80
+BME280_OVERS_T16         = 0xA0
+
+BME280_OVERS_P1          = 0x04
+BME280_OVERS_P2          = 0x08
+BME280_OVERS_P4          = 0x0C
+BME280_OVERS_P8          = 0x10
+BME280_OVERS_P16         = 0x14
+
+BME280_OVERS_H1          = 0x01
+BME280_OVERS_H2          = 0x02
+BME280_OVERS_H4          = 0x03
+BME280_OVERS_H8          = 0x04
+BME280_OVERS_H16         = 0x05
+
+# Power Modes.
+# This lib uses NORMAL mode only!
+#BME280_SLEEP_MODE        = 0x00
+#BME280_FORCED_MODE       = 0x01
+BME280_NORMAL_MODE       = 0x03
+
+BME280_TSB_0_5           = 0x00
+BME280_TSB_62_5          = 0x20
+BME280_TSB_125           = 0x40
+BME280_TSB_250           = 0x60
+BME280_TSB_500           = 0x80
+BME280_TSB_1000          = 0xA0
+BME280_TSB_2000          = 0xC0
+BME280_TSB_4000          = 0xE0
+
+BME280_FILTER_OFF                = 0x00
+BME280_FILTER_COEFFICIENT2       = 0x04
+BME280_FILTER_COEFFICIENT4       = 0x08
+BME280_FILTER_COEFFICIENT8       = 0x0C
+BME280_FILTER_COEFFICIENT16      = 0x10
+
+BME280_SPI_OFF           = 0x00
+BME280_SPI_ON            = 0x01
+
+BME280_CONTROL_MEAS_SET       = (BME280_OVERS_T16 | BME280_OVERS_P16 | BME280_NORMAL_MODE)
+BME280_CONTROL_HUM_SET = BME280_OVERS_H2
+BME280_CONFIG_SET        = (BME280_TSB_0_5 | BME280_FILTER_COEFFICIENT16 | BME280_SPI_OFF)
+
+class BME280(object):
+       def __init__(self, port=1, address=BME280_I2CADDR):
+               self.bus = smbus.SMBus(port)
+               self.address = address
+
+               # Read calibration values
+               self.dig_t1 = self.read_word(BME280_DIG_T1)      # Unsigned
+               self.dig_t2 = self.read_word_sign(BME280_DIG_T2)
+               self.dig_t3 = self.read_word_sign(BME280_DIG_T3)
+               self.dig_p1 = self.read_word(BME280_DIG_P1)      # Unsigned
+               self.dig_p2 = self.read_word_sign(BME280_DIG_P2)
+               self.dig_p3 = self.read_word_sign(BME280_DIG_P3)
+               self.dig_p4 = self.read_word_sign(BME280_DIG_P4)
+               self.dig_p5 = self.read_word_sign(BME280_DIG_P5)
+               self.dig_p6 = self.read_word_sign(BME280_DIG_P6)
+               self.dig_p7 = self.read_word_sign(BME280_DIG_P7)
+               self.dig_p8 = self.read_word_sign(BME280_DIG_P8)
+               self.dig_p9 = self.read_word_sign(BME280_DIG_P9)
+
+               self.dig_h1 = self.read_byte(BME280_DIG_H1)     # unsigned char
+               self.dig_h2 = self.read_word_sign(BME280_DIG_H2)
+               self.dig_h3 = self.read_byte(BME280_DIG_H3)     # unsigned char
+
+               self.dig_h4 = (self.read_byte(BME280_DIG_H4) << 24) >> 20
+               self.dig_h4 = self.dig_h4 | self.read_byte(BME280_DIG_H4+1) & 0x0F
+
+               self.dig_h5 = (self.read_byte(BME280_DIG_H5+1) << 24) >> 20
+               self.dig_h5 = self.dig_h5 | (self.read_byte(BME280_DIG_H5) >> 4) & 0x0F
+
+               self.dig_h6 = self.read_byte(BME280_DIG_H6)     # signed char
+               if self.dig_h6 > 127:
+                       self.dig_h6 = 127-self.dig_h6
+
+               # Set Configuration
+                self.write_byte(BME280_CONFIG, BME280_CONFIG_SET)
+               self.write_byte(BME280_CONTROL_HUM, BME280_CONTROL_HUM_SET)
+               self.write_byte(BME280_CONTROL_MEAS, BME280_CONTROL_MEAS_SET)
+
+       def get_data(self):
+               adc_t = self.read_adc_long(BME280_TEMP)
+               adc_p = self.read_adc_long(BME280_PRESSURE)
+               adc_h = self.read_adc_word(BME280_HUMIDITY)
+
+               var1 = (adc_t/16384.0 - self.dig_t1/1024.0) * self.dig_t2;
+               var2 = ((adc_t/131072.0 - self.dig_t1/8192.0) * (adc_t/131072.0 - self.dig_t1/8192.0)) * self.dig_t3;
+               t_fine = (var1 + var2);
+               temperature = round((t_fine / 5120.0), 2);
+
+               var1 = (t_fine/2.0) - 64000.0;
+               var2 = var1 * var1 * self.dig_p6 / 32768.0;
+               var2 = var2 + var1 * self.dig_p5 * 2.0;
+               var2 = (var2/4.0)+(self.dig_p4 * 65536.0);
+               var1 = (self.dig_p3 * var1 * var1 / 524288.0 + self.dig_p2 * var1) / 524288.0;
+               var1 = (1.0 + var1 / 32768.0)*self.dig_p1;
+
+               # Avoid exception caused by division by zero
+               if (var1 == 0.0):
+                       return -1
+
+               p = 1048576.0 - adc_p;
+               p = (p - (var2 / 4096.0)) * 6250.0 / var1;
+               var1 = self.dig_p9 * p * p / 2147483648.0;
+               var2 = p * self.dig_p8 / 32768.0;
+               pressure = round((p + (var1 + var2 + self.dig_p7) / 16.0), 2);
+
+               var_H = t_fine - 76800.0
+               var_H = (adc_h-(self.dig_h4*64.0+self.dig_h5 / 16384.0 * var_H))*(self.dig_h2/65536.0 * (1.0 + self.dig_h6/67108864.0 * var_H * (1.0+self.dig_h3/67108864.0 * var_H)))
+               humidity = round(var_H * (1.0 - self.dig_h1*var_H/524288.0), 2)
+               if (humidity > 100.0):
+                       humidity = 100.0
+               else:
+                       if(humidity < 0.0):
+                               humidity = 0.0
+
+               return {'t':temperature, 'p':pressure, 'h':humidity}
+
+       def get_altitude(self, pressure):
+               temp = pressure/101325;
+               temp = 1-pow(temp, 0.19029);
+               altitude = round(44330*temp, 3);
+               return altitude;
+
+       def read_byte(self, adr):
+               return self.bus.read_byte_data(self.address, adr)
+
+       def read_word(self, adr):
+               # ATANTION! Joke from Bosch! LBS before HBS. For calibration registers only!
+               lbs = self.bus.read_byte_data(self.address, adr)
+               hbs = self.bus.read_byte_data(self.address, adr+1)
+               return (hbs << 8) + lbs
+
+       def read_word_sign(self, adr):
+               val = self.read_word(adr)
+               if (val >= 0x8000):
+                       return -((65535 - val) + 1)
+               else:
+                       return val
+
+       def read_adc_long(self, adr):
+               mbs = self.bus.read_byte_data(self.address, adr)
+               lbs = self.bus.read_byte_data(self.address, adr+1)
+               xbs = self.bus.read_byte_data(self.address, adr+2)
+               val = (mbs << 16) + (lbs << 8) + xbs
+               val = (val >> 4)
+               return val
+
+        def read_adc_word(self, adr):
+                mbs = self.bus.read_byte_data(self.address, adr)
+                lbs = self.bus.read_byte_data(self.address, adr+1)
+                val = (mbs << 8) + lbs
+                return val
+
+       def write_byte(self, adr, byte):
+               self.bus.write_byte_data(self.address, adr, byte)
diff --git a/bin/lcdproc.expect b/bin/lcdproc.expect
new file mode 100755 (executable)
index 0000000..28235e6
--- /dev/null
@@ -0,0 +1,117 @@
+#!/usr/bin/expect
+
+proc lcdcmd {sid cmd} {
+  send -i ${sid} "${cmd}\n"
+  while { true } {
+    expect {
+      -i ${sid} -re "^[lindex [split "${cmd}"] 0]\[^\n\]*\r\n" {
+         while { true } {
+           expect {
+             -i ${sid} -re "^success\[^\n\]*\n" { return }
+             -i ${sid} -re "^\r\n" { }
+             -i ${sid} -re "^listen .*\n" {}
+             -i ${sid} -re "^ignore .*\n" {}
+             timeout { error "LCD protocol failure while waiting for success?" } 
+           }
+         }
+       }
+      -i ${sid} -re "^listen .*\n" {}
+      -i ${sid} -re "^ignore .*\n" {}
+      timeout { error "LCD protocol failure while waiting for echo?" } 
+    }
+  }
+}
+
+proc spawnlcd {host port} {
+  spawn socat STDIO "TCP:${host}:${port}"
+  send -i ${spawn_id} "hello\n"
+  expect {
+    -i ${spawn_id} -re "^hello\r\nconnect .*\r\n" { return ${spawn_id} }
+    timeout { error "LCD protocol failure while sending hello?" } 
+  }
+}
+
+spawn tail --retry --follow=name /run/snakecontrol/monitor.log/current
+set logsid ${spawn_id}
+
+set sid [spawnlcd "localhost" "13666"]
+lcdcmd ${sid} "client_set -name test"
+
+lcdcmd ${sid} "screen_add 1"
+lcdcmd ${sid} "screen_set 1 -name Vivarium"
+lcdcmd ${sid} "screen_set 1 -priority hidden"
+lcdcmd ${sid} "screen_set 1 -cursor off"
+
+lcdcmd ${sid} "widget_add 1 ti title"
+lcdcmd ${sid} "widget_set 1 ti Vivarium"
+
+lcdcmd ${sid} "widget_add 1 i_up icon"
+lcdcmd ${sid} "widget_set 1 i_up 1 2 ARROW_UP"
+lcdcmd ${sid} "widget_add 1 i_th string"
+lcdcmd ${sid} "widget_set 1 i_th 2 2 T"
+lcdcmd ${sid} "widget_add 1 v_ut string"
+lcdcmd ${sid} "widget_add 1 i_uh string"
+lcdcmd ${sid} "widget_set 1 i_uh 8 2 H"
+lcdcmd ${sid} "widget_add 1 v_uh string"
+
+lcdcmd ${sid} "widget_add 1 i_l icon"
+lcdcmd ${sid} "widget_set 1 i_l 1 3 ARROW_LEFT"
+
+lcdcmd ${sid} "widget_add 1 i_r icon"
+lcdcmd ${sid} "widget_set 1 i_r 1 4 ARROW_RIGHT"
+
+lcdcmd ${sid} "widget_add 1 i_lh icon"
+lcdcmd ${sid} "widget_set 1 i_lh 2 3 ARROW_DOWN"
+lcdcmd ${sid} "widget_add 1 v_lh string"
+
+lcdcmd ${sid} "widget_add 1 i_rh icon"
+lcdcmd ${sid} "widget_set 1 i_rh 2 4 ARROW_DOWN"
+lcdcmd ${sid} "widget_add 1 v_rh string"
+
+lcdcmd ${sid} "widget_add 1 i_lt icon"
+lcdcmd ${sid} "widget_set 1 i_lt 9 3 ARROW_UP"
+lcdcmd ${sid} "widget_add 1 v_lt string"
+
+lcdcmd ${sid} "widget_add 1 i_rt icon"
+lcdcmd ${sid} "widget_set 1 i_rt 9 4 ARROW_UP"
+lcdcmd ${sid} "widget_add 1 v_rt string"
+
+lcdcmd ${sid} "widget_add 1 v_ldmxl string"
+lcdcmd ${sid} "widget_set 1 v_ldmxl 17 3 @"
+lcdcmd ${sid} "widget_add 1 v_ldmx string"
+lcdcmd ${sid} "widget_add 1 v_rdmxl string"
+lcdcmd ${sid} "widget_set 1 v_rdmxl 17 4 @"
+lcdcmd ${sid} "widget_add 1 v_rdmx string"
+
+lcdcmd ${sid} "screen_set 1 -priority info"
+
+proc drawtemp { scr wid x y } {
+  global sid
+  global expect_out
+  set t [expr round(${expect_out(1,string)}*10.0)/10.0]
+  lcdcmd ${sid} "widget_set ${scr} ${wid} ${x} ${y} ${t}"
+}
+
+set datapfx "^\[^ \]* DATA: "
+set datare "(\[^ \r\n]*)"
+
+while { true } {
+  expect {
+    -i ${logsid} -re "${datapfx}hide-near.* temp=${datare}.*\n"  { drawtemp 1 "v_lh" 4  3 }
+    -i ${logsid} -re "${datapfx}hide-far.* temp=${datare}.*\n"   { drawtemp 1 "v_rh" 4  4 }
+    -i ${logsid} -re "${datapfx}tank-near.* temp=${datare}.*\n"  { drawtemp 1 "v_lt" 11 3 }
+    -i ${logsid} -re "${datapfx}tank-far.* temp=${datare}.*\n"   { drawtemp 1 "v_rt" 11 4 }
+    -i ${logsid} -re "${datapfx}tank-top.* temp=${datare}.*\n"   { drawtemp 1 "v_ut" 3  2 }
+    -i ${logsid} -re "${datapfx}tank-top.* humid=${datare}.*\n"  { drawtemp 1 "v_uh" 9  2 }
+    -i ${logsid} -re "${datapfx}dmx-near.* dmx=${datare}.*\n" {
+      lcdcmd ${sid} "widget_set 1 v_ldmx 18 3 ${expect_out(1,string)}"
+    }
+    -i ${logsid} -re "${datapfx}dmx-mid.* dmx=${datare}.*\n" {
+      lcdcmd ${sid} "widget_set 1 v_rdmx 18 4 ${expect_out(1,string)}"
+    }
+    -i ${logsid} -re "\n" {}
+    -i ${sid} -re "^listen .*\n" {}
+    -i ${sid} -re "^ignore .*\n" {}
+  }
+}
index dbfa8c3b96ef4be1e7edd053e526328b1ee61b11..dc2073eff5d47b364eb91f72e8bc048bf06b7d43 100755 (executable)
@@ -2,4 +2,4 @@
 
 echo "Content-Type: text/plain"
 echo
-exec tail -n 40 /home/pi/sc/data/monitor.log/current
+exec tail -n 40 /run/snakecontrol/monitor.log/current
diff --git a/bin/monitor.py b/bin/monitor.py
deleted file mode 100755 (executable)
index 087db67..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/usr/bin/python
-
-# Inspired by code found at http://wannabe.guru.org/scott/hobbies/temperature/
-
-import os
-import rrdtool
-import sched
-import time
-
-owdev_logname = {
-    "/sys/bus/w1/devices/28-011620c718ee/w1_slave" : "/home/pi/sc/data/hide-far-temp.rrd",
-    "/sys/bus/w1/devices/28-011620f10dee/w1_slave" : "/home/pi/sc/data/hide-near-temp.rrd",
-    "/sys/bus/w1/devices/28-02161e26acee/w1_slave" : "/home/pi/sc/data/tank-far-temp.rrd",
-    "/sys/bus/w1/devices/28-03164712aaff/w1_slave" : "/home/pi/sc/data/heater-temp.rrd",
-    "/sys/bus/w1/devices/28-0416526de6ff/w1_slave" : "/home/pi/sc/data/tank-near-temp.rrd",
-}
-
-owdev_thresholds_heater1 = {
-     "/sys/bus/w1/devices/28-011620c718ee/w1_slave" : (23.0, 25.0), # hide far
-     "/sys/bus/w1/devices/28-02161e26acee/w1_slave" : (21.0, 25.0), # tank air far
-     "/sys/bus/w1/devices/28-0416526de6ff/w1_slave" : (23.0, 27.0), # tank air near
-}
-
-# owdev_thresholds_heater2 = {
-#     "/sys/bus/w1/devices/28-011620f10dee/w1_slave" : (29.0, 29.5), # hide near
-# }
-
-def nop (*arg, **kwarg):
-    pass
-
-def with_ow_temp_fk_id(devfn, x, *arg, **kwarg):
-    print("WARNING: failed to read %s" % devfn)
-    return x
-
-def with_ow_temp(devfn, sk, fk, *arg, **kwarg):
-    with open(devfn) as devf:
-        devstr = devf.read()
-        devlines = devstr.split("\n")
-        if devlines[0].find("YES") > 0:
-            return sk(devfn,float((devlines[1].split(" ")[9])[2:]) / 1000, *arg, **kwarg)
-    return fk(devfn, *arg, **kwarg)
-
-
-def check_temps(sc):
-    print ("check temps init")
-    def check(devfn, temp, threshs, desire):
-        # Anything too hot: turn off the heater
-        if (temp > threshs[devfn][1]): desire = "OFF"
-        # No stated preference and something too cold, turn on the heater
-        elif (temp <= threshs[devfn][0] and desire == None): desire = "ON"
-        return desire
-
-    did_interact = False
-    desire = None
-    for devfn in owdev_thresholds_heater1:
-        desire = with_ow_temp(devfn, check, with_ow_temp_fk_id, owdev_thresholds_heater1, desire)
-    if desire is not None:
-        did_interact = True
-        print("Set heater 1 %s" % desire)
-        os.system("/home/pi/sc/bin/rpb.expect 4 %s | grep -A 5 -e 'Plug ' | tr -d '\015'" % desire)
-
-    # desire = None
-    # for devfn in owdev_thresholds_heater2:
-    #     desire = with_ow_temp(devfn, check, with_ow_temp_fk_id, owdev_thresholds_heater2, desire)
-    # if desire is not None:
-    #     did_interact = True
-    #     print("Set heater 2 %s" % desire)
-    #     os.system("/home/pi/sc/bin/rpb.expect 5 %s | grep -A 5 -e 'Plug ' | tr -d '\015'" % desire)
-
-    if not did_interact:
-        os.system("/home/pi/sc/bin/rpb.expect | grep -A 5 -e 'Plug ' | tr -d '\015'")
-
-    sc.enter(300, 1, check_temps, (sc,))
-    print ("check temps fini")
-
-def do_log_temp(devfn, temp):
-    print("temp log: %s => %f" % (devfn, temp))
-    rrdtool.update(owdev_logname[devfn], "N:" + ("%f" % temp))
-
-def read_temps(sc,itime): 
-    for devfn in owdev_logname: with_ow_temp(devfn, do_log_temp, nop)
-    itime = itime + 60
-    sc.enterabs(itime, 2, read_temps, (sc,itime))
-
-itime = time.time()
-s = sched.scheduler(time.time, time.sleep)
-s.enterabs(itime, 1, check_temps, (s,))
-s.enterabs(itime, 2, read_temps, (s,itime))
-
-print("Monitor starting...")
-s.run()
index 6dd831736cba6fadee07743da46852a00bd36983..192bcc4edd52ebf1ee01d1948f7751fb090e2636 100644 (file)
@@ -45,7 +45,7 @@ class PIDLoop(object):
 
     def _value (self, error, edeltasmooth) :
 
-        print ("PID LOOP CONTRIBUTIONS: p=%r d=%r i=%r" % (self.kP * error, self.kD * edeltasmooth, self.kI * self.sum_error))
+        print ("PID LOOP CONTRIBUTIONS: p=%r d=%r i=%r" % (self.kP * error, self.kD * edeltasmooth, self.kI * self.sum_error))
 
         return (self.kP * error) + (self.kD * edeltasmooth) + (self.kI * self.sum_error)
 
@@ -78,7 +78,7 @@ class PIDLoop(object):
         elif self.hard_min is not None and ov <= self.hard_min and sum_error_delta < 0:
             # Do not decrement error; we're already slammed up against the hard limit
             pass
-        else if sum_error_delta != 0:
+        elif sum_error_delta != 0:
             # Update sum_error and recompute the output value
             self.sum_error += sum_error_delta
             ov = self._value(error, edeltasmooth)
index d15ca747f2a4217e16705c5d43282c2ecf1733b0..2603ed1ea6080efe20e10a992d9f49ba20d11680 100755 (executable)
@@ -6,9 +6,11 @@ import os
 import sched
 import time
 import serial
-import pidloop
 import rrdtool
 
+import pidloop
+import BME280
+
 dmxdev = serial.Serial("/dev/serial/by-id/usb-DMXking.com_DMX_USB_PRO_6A0SVM7J-if00-port0", 57600);
 
 loop_hidenear = pidloop.PIDThresh(128,26,28,0,31,33,-128)
@@ -18,24 +20,70 @@ loop_hidenear.setHardMin(-128)
 loop_hidenear.setKP(60.0)
 loop_hidenear.setKI(0.004)
 loop_hidenear.setKD(1000.0,0.95) 
-loop_hidenear.sum_error = -3000.0 # XXX Initialize offset point a bit
+loop_hidenear.sum_error = -7600.0 # XXX Initialize offset point a bit
+
+bmetop = BME280.BME280(port=1, address=0x77)
 
-def with_ow_temp_fk_id(devfn, loop, s, *arg, **kwarg):
+def with_ow_temp_fk_id2(devfn, loop, s, *arg, **kwarg):
     print("WARNING: failed to read %s" % devfn)
     return s # an ugly default
 
-def with_ow_temp(devfn, sk, fk, *arg, **kwarg):
+def with_ow_temp(cache, devfn, sk, fk, *arg, **kwarg):
+    if devfn in cache :
+        return sk(devfn, cache[devfn], *arg, **kwarg)
     with open(devfn) as devf:
         devstr = devf.read()
         devlines = devstr.split("\n")
         if devlines[0].find("YES") > 0:
-            return sk(devfn,float((devlines[1].split(" ")[9])[2:]) / 1000, *arg, **kwarg)
+            val = float((devlines[1].split(" ")[9])[2:]) / 1000
+            cache[devfn] = val
+            return sk(devfn, val, *arg, **kwarg)
     return fk(devfn, *arg, **kwarg)
 
 def check_temps(sc):
     sc.enter(10, 1, check_temps, (sc,))
 
-    def check(devfn, temp, loop, s, offset, rrd):
+    cache = {}
+
+    def log(devfn, temp, logname, rrd, kw="temp"):
+        rrdtool.update(rrd, "N:" + ("%f" % temp))
+        print ("DATA: %s %s=%s" % (logname, kw, temp))
+
+    def logfail(devfn, name, *arg):
+        print ("FAIL: %s %s %s" % (name, devfn, arg))
+
+    # BME280 atop
+    try:
+      top = bmetop.get_data()
+      log("bme280-77", top['t'], "tank-top", "/home/pi/sc/data/tank-top-temp.rrd")
+      log("bme280-77", top['h'], "tank-top", "/home/pi/sc/data/tank-top-humid.rrd", kw="humid")
+      log("bme280-77", top['p'], "tank-top", "/home/pi/sc/data/tank-top-press.rrd", kw="press")
+    except Exception, e:
+      logfail("bme280-77", "hide-top")
+
+    # Log (and populate cache, while we're at it)
+    with_ow_temp(cache,
+                 "/sys/bus/w1/devices/28-011620f10dee/w1_slave", log, logfail,
+                 "hide-near", "/home/pi/sc/data/hide-near-temp.rrd")
+
+    with_ow_temp(cache,
+                 "/sys/bus/w1/devices/28-011620c718ee/w1_slave", log, logfail,
+                 "hide-far", "/home/pi/sc/data/hide-far-temp.rrd")
+
+    with_ow_temp(cache,
+                 "/sys/bus/w1/devices/28-02161e26acee/w1_slave", log, logfail,
+                 "tank-far", "/home/pi/sc/data/tank-far-temp.rrd")
+
+    with_ow_temp(cache,
+                 "/sys/bus/w1/devices/28-03164712aaff/w1_slave", log, logfail,
+                 "heater-near", "/home/pi/sc/data/heater-temp.rrd")
+
+    with_ow_temp(cache,
+                 "/sys/bus/w1/devices/28-0416526de6ff/w1_slave", log, logfail,
+                 "tank-near", "/home/pi/sc/data/tank-near-temp.rrd")
+
+
+    def checkpid(devfn, temp, loop, s, offset, rrd, logname):
         desire = 128.0 + loop.update(temp, time.time())
 
         if desire < 0 :
@@ -46,8 +94,10 @@ def check_temps(sc):
             loop.output = 255
 
         rrdtool.update(rrd, "N:" + ("%f" % desire))
+        dmx = int(desire+0.5)
+        print("DATA: %s dmx=%s" % (logname, dmx))
 
-        return s[:offset] + chr(int(desire+0.5)) + s[offset+1:]
+        return s[:offset] + chr(dmx) + s[offset+1:]
 
     # DMX conttrol string; initialize to all channels full off
     # 7E -- header
@@ -60,8 +110,10 @@ def check_temps(sc):
     s = "\x7E\x06\x03\x00\x00\x00\x00\xE7"
 
     # Drive loop
-    s = with_ow_temp("/sys/bus/w1/devices/28-011620f10dee/w1_slave",
-            check, with_ow_temp_fk_id, loop_hidenear, s, 5, "/home/pi/sc/data/hide-near-dmx.rrd")
+    s = with_ow_temp(cache, "/sys/bus/w1/devices/28-011620f10dee/w1_slave",
+            checkpid, with_ow_temp_fk_id2, loop_hidenear, s, 5, "/home/pi/sc/data/hide-near-dmx.rrd", "dmx-near")
+
+    # Log some other probes
 
     print ("check temps fini: out=%r lhn=(%s)" % (s, loop_hidenear))
     assert(dmxdev.write(s) == 8)
index 78bc5fb38cc250bf5f0fe32b2fa7c05d95fc44ea..eb383301ff96ef6363ab66802bfb24b81fde4f8d 100755 (executable)
@@ -6,6 +6,7 @@ RRDS=(
  hide-far-temp
  tank-near-temp
  tank-far-temp
+ tank-top-temp
 )
 
 ARGS=(
@@ -39,3 +40,22 @@ ARGS=(
 for rrd in ${=RRDS[@]}; do
   rrdtool create /home/pi/sc/data/${rrd}.rrd ${=ARGS[@]}
 done
+
+rrdtool create /home/pi/sc/data/tank-top-humid.rrd \
+   --no-overwrite \
+   --step 60 \
+   DS:humid:GAUGE:900:-5:105 \
+   RRA:AVERAGE:0.5:6:525600 \
+   RRA:AVERAGE:0.25:360:87600 \
+   RRA:MIN:0.025:360:87600 \
+   RRA:MAX:0.025:360:87600
+
+
+rrdtool create /home/pi/sc/data/tank-top-press.rrd \
+   --no-overwrite \
+   --step 60 \
+   DS:press:GAUGE:900:-1000:120000 \
+   RRA:AVERAGE:0.5:6:525600 \
+   RRA:AVERAGE:0.25:360:87600 \
+   RRA:MIN:0.025:360:87600 \
+   RRA:MAX:0.025:360:87600
index a46a4f0ce61be60eb2a519772ea6b2a3d0ace79d..09173cc7af6c2404b08d88a969bd34b135c831ce 100644 (file)
@@ -1,2 +1 @@
 *.rrd
-monitor.log
diff --git a/runit/pi-sc-lcd/run b/runit/pi-sc-lcd/run
new file mode 100755 (executable)
index 0000000..53844d8
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec chpst -u pi:pi expect /home/pi/sc/bin/lcdproc.expect >/dev/null
index e6b7e1760b82524f7f35241c4abd277d7b7f44bb..da5928de41130078132064e497da5015edc8f206 100755 (executable)
@@ -1,2 +1,4 @@
 #!/bin/sh
-exec chpst -u pi svlogd -tt /home/pi/sc/data/monitor.log
+mkdir -p /run/snakecontrol/monitor.log
+chown -R pi:pi /run/snakecontrol
+exec chpst -u pi svlogd -tt /run/snakecontrol/monitor.log
index 10a6247eb38cbb1eb264ef090a2b7dc58051f082..0b985221ebec960c62cfcd49c796cb2ec0f69aa1 100755 (executable)
@@ -1,2 +1,2 @@
 #!/bin/sh
-exec chpst -u pi:pi:dialout python -u /home/pi/sc/bin/monitor.py
+exec chpst -u pi:pi:dialout:i2c python -u /home/pi/sc/bin/pidmonitor.py