diff --git a/examples/__pycache__/weather_station.cpython-39.pyc b/examples/__pycache__/weather_station.cpython-39.pyc new file mode 100644 index 0000000..c80ff9b Binary files /dev/null and b/examples/__pycache__/weather_station.cpython-39.pyc differ diff --git a/examples/python/sara_example/__pycache__/expresslink.cpython-39.pyc b/examples/python/sara_example/__pycache__/expresslink.cpython-39.pyc new file mode 100644 index 0000000..7dbdbc0 Binary files /dev/null and b/examples/python/sara_example/__pycache__/expresslink.cpython-39.pyc differ diff --git a/examples/python/sara_example/__pycache__/weather_station.cpython-39.pyc b/examples/python/sara_example/__pycache__/weather_station.cpython-39.pyc new file mode 100644 index 0000000..2fc3730 Binary files /dev/null and b/examples/python/sara_example/__pycache__/weather_station.cpython-39.pyc differ diff --git a/examples/python/sara_example/code.py b/examples/python/sara_example/code.py index d11aa8c..f6efddf 100644 --- a/examples/python/sara_example/code.py +++ b/examples/python/sara_example/code.py @@ -6,28 +6,32 @@ from countio import Counter, Edge from digitalio import DigitalInOut, Direction, Pull from analogio import AnalogIn +from weather_station import weather_station from expresslink import ExpressLink time.sleep(2) print("WeatherStation Startup") +def celsius2fahrenheit(celsius:float)->float: + return ((celsius * 9.0)/5.0) + 32.0 + def GetVoltage(pin): return (pin.value * 3.3) / 65536 # Resistor table -resistorTable = (('N',33000), ('NNE',6570), ('NE',8200), ('ENE',891), ('E',1000), ('ESE',688), ('SE',2200),('SSE',1410),('S',3900),('SSW',3140),('SW',16000),('WSW', 14120),('W',120000),('WNW',42120),('NW',64900), ('NNW', 21880)) +resistorTable = ((0,33000), (22.5,6570), (45,8200), (67.5,891), (90,1000), (112.5,688), (135,2200),(157.5,1410),(180,3900),(202.5,3140),(225,16000),(247.5, 14120),(270,120000),(292.5,42120),(315,64900), (337.5, 21880)) # Compute correct Resistance # Top resistor 10k # Supply voltage is 3.3v # R = (v * 10000)/(3.3-v) -def getDirection(pin)->str: +def getDirection(pin)->float: v = GetVoltage(pin) r = (v * 10000.0) / (3.3 - v) smallestValue = 10000000 - direction = "" + direction = 0.0 for entry in resistorTable: distance = abs(r - entry[1]) if distance < smallestValue: @@ -35,21 +39,19 @@ def getDirection(pin)->str: smallestValue = distance return direction -lastTime = 0 -oldSpeed = 0 +lastTime = time.time() def getSpeed(pin:Counter)->float: - global lastTime, oldSpeed + global lastTime thisTime = time.time() deltaTime = thisTime - lastTime - if deltaTime > 10: - windCount = pin.count - pin.reset() - lastTime = thisTime - hz = windCount / deltaTime - oldSpeed = 2.4 * hz # km/hr - return oldSpeed - -lastTip = 0 + windSpeed = pin.count / deltaTime + pin.reset() + lastTime = thisTime + windSpeed *= 1.492 + return windSpeed # return wind speed in mph + +# todo: fix rain reset for 24 hours. use absolute time from expreslink +lastTip = time.time() previousTipCount = 0 def getRainDepth(pin:Counter)->float: global lastTip, previousTipCount @@ -63,8 +65,9 @@ def getRainDepth(pin:Counter)->float: pin.reset() # reset the count previousTipCount = 0 tips = 0 - return tips * 0.2794 # depth in mm + return ( tips * 0.2794 ) / 25.4 # depth in in +ws = weather_station() windDirection = AnalogIn(board.A0) @@ -75,6 +78,10 @@ def getRainDepth(pin:Counter)->float: print("ExpressLink Started") +led = DigitalInOut(board.G10) +led.direction = Direction.OUTPUT + + i2c = board.I2C() bme680 = adafruit_bme680.Adafruit_BME680_I2C(i2c,debug=False) @@ -89,22 +96,37 @@ def getRainDepth(pin:Counter)->float: thingName = response[3:] response = el.sendCommand("AT+CONF Topic1=/weather/sensor/" + thingName) +reportCounter = 60 while True: - - if el.connect(): - report = {} - report["temperature"] = bme680.temperature+temperature_offset - report["gas"] = bme680.gas - report["humidity"] = bme680.relative_humidity - report["pressure"] = bme680.pressure - report["wind direction"] = getDirection(windDirection) - report["wind speed"] = getSpeed(wind) - report["rain"] = getRainDepth(rain) - data = json.dumps(report) - print("Reporting : " + data) - el.sendCommand("AT+SEND1 " + data) - else: - print("No connection") - el.begin() - - time.sleep(1) \ No newline at end of file + led.value = True + reportCounter -= 1 + + ws.addWind(getSpeed(wind), getDirection(windDirection)) + + if reportCounter == 0: + if el.connect() and reportCounter == 0: + reportCounter = 60 + report = {} + report["tempf"] = celsius2fahrenheit( bme680.temperature+temperature_offset ) + report["humidity"] = bme680.relative_humidity + report["pressure"] = bme680.pressure + report["winddir"] = ws.windDirection + report["windspeedmph"] = ws.windSpeed + report["windgustmph"] = ws.windGust1minSpeed + report["windgustdir"] = ws.windGust1minDirection + report["windspdmph_avg2m"] = ws.wind2MinAverageMPH + report["winddir_avg2m"] = ws.wind2MinAverageDirection + report["windgustmph_10m"] = ws.wind10MinGustMPH + report["windgustdir_10m"] = ws.wind10MinGustDirection + report["dailyrainin"] = getRainDepth(rain) + data = json.dumps(report) + print("Reporting : " + data) + el.sendCommand("AT+SEND1 " + data) + else: + reportCounter = 2 # try again in 2 seconds + print("No connection") + + # ensure the LED blink is noticable + time.sleep(.5) + led.value = False + time.sleep(.5) \ No newline at end of file diff --git a/examples/python/sara_example/station_test.py b/examples/python/sara_example/station_test.py new file mode 100644 index 0000000..2a22ed9 --- /dev/null +++ b/examples/python/sara_example/station_test.py @@ -0,0 +1,80 @@ +from weather_station import weather_station +import random +import time + +direction = [ 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0,350.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, +] + +ws= weather_station() + +for d in direction: + ws.addWind( random.random() * 50.0, d ) + +print("gust speed " + str(ws.windGust1minSpeed)) +print("gust direction " + str(ws.windGust1minDirection)) +print("10 min gust speed " + str(ws.wind10MinGustMPH)) +print("10 min gust direction " + str(ws.wind10MinGustDirection)) diff --git a/examples/python/sara_example/weather_station.py b/examples/python/sara_example/weather_station.py new file mode 100644 index 0000000..243be87 --- /dev/null +++ b/examples/python/sara_example/weather_station.py @@ -0,0 +1,95 @@ +import time + +class weather_station: + windGust1minSpeed:float + windGust1minDirection:float + windDataSpeed = [] + windDataDirection = [] + windGust = [] + gustDataCounter:int + windDataCounter:int + + # report this information + windSpeed:float + windDirection:float + wind2MinAverageMPH:float + wind2MinAverageDirection:float + wind10MinGustMPH:float + wind10MinGustDirection:float + + def __init__(self): + print("starting weather station") + self.windGust1minSpeed = 0.0 + self.gustDataCounter = 60 + self.windDataCounter = 120 + self.windGust1minDirection = 0.0 + self.windGust1minSpeed = 0.0 + self.wind2MinAverageMPH = 0.0 + self.wind2MinAverageDirection = 0.0 + self.wind10MinGustDirection = 0.0 + self.wind10MinGustMPH = 0.0 + self.windSpeed = 0.0 + self.windDirection = 0.0 + + # run every 1 minute assumes it is called every second + def _doGusts(self, speed: float, direction:float): + self.gustDataCounter -= 1 + if speed > self.windGust1minSpeed: + self.windGust1minSpeed = speed + self.windGust1minDirection = direction + + if self.gustDataCounter == 0: + self.gustDataCounter = 60 + # update the 10 minute wind gust statistics every minute + gdata = (self.windGust1minSpeed, self.windGust1minDirection) + self.windGust.append( gdata ) + self.windGust1minSpeed = 0 + while len(self.windGust) > 10: # ensure we only have 10 minutes of data + self.windGust.pop(0) + gust = (0.0,0.0) + for g in self.windGust: + if g[0] > gust[0]: + gust = g + self.wind10MinGustMPH = gust[0] + self.wind10MinGustDirection = gust[1] + + def addWind(self, speed: float , direction:float): + self.windDataCounter -= 1 + self.windSpeed = speed + self.windDirection = direction + self.windDataSpeed.append( speed ) + self.windDataDirection.append( direction ) + + self._doGusts(speed,direction) + + if self.windDataCounter == 0: + self.windDataCounter = 120 + # time to compute wind statistics (every 2 minutes) + self._calcWeather() + self.windDataDirection.clear() + self.windDataSpeed.clear() + + def _addDirection(self, direction1:float, direction2:float )->float: + delta = direction1 - direction2 + if delta < -180.0: + return delta + 360 + elif delta > 180.0: + return delta - 360 + else: + return delta + + def _calcWeather(self): + speedAverage = 0 + for w in self.windDataSpeed: + speedAverage += w + self.wind2MinAverageMPH = speedAverage / len(self.windDataSpeed) + + sum = self.windDataDirection[0] + D = self.windDataDirection[0] + for d in self.windDataDirection[1:]: + D += self._addDirection(d, D) + sum += D + self.wind2MinAverageDirection = sum / len(self.windDataDirection) + + +