Skip to content

Commit

Permalink
Merge pull request #6 from garbled1/new_api
Browse files Browse the repository at this point in the history
New api, Bump to 0.20
  • Loading branch information
garbled1 authored Nov 28, 2021
2 parents 5dccef5 + a9d15a6 commit 86439f5
Show file tree
Hide file tree
Showing 5 changed files with 954 additions and 8 deletions.
1 change: 1 addition & 0 deletions pyecowitt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
__copyright__ = "Copyright (c) 2020,2021 Tim Rightnour"

from .ecowitt import (
EcoWittSensor,
EcoWittListener,
WINDCHILL_OLD,
WINDCHILL_NEW,
Expand Down
2 changes: 1 addition & 1 deletion pyecowitt/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import ecowitt
import pyecowitt as ecowitt
import asyncio
import sys

Expand Down
144 changes: 137 additions & 7 deletions pyecowitt/ecowitt.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,81 @@
"""
Setup a bone simple webserver, listen to POST's from a device like a
GW1000 or in my case, HP3501, decode results.
"""

import asyncio
from aiohttp import web
import logging
import math
import time

"""
Setup a bone simple webserver, listen to POST's from a device like a
GW1000 or in my case, HP3501, decode results.
"""

from .sensor_map import (
EcoWittSensorTypes,
MAP_NAME as MAP_NAME,
MAP_SYSTEM as MAP_SYSTEM,
MAP_STYPE as MAP_STYPE,
SENSOR_MAP as SENSOR_MAP
)

ECOWITT_LISTEN_PORT = 4199
WINDCHILL_OLD = 0
WINDCHILL_NEW = 1
WINDCHILL_HYBRID = 2


class EcoWittSensor:
"""An internal sensor to the ecowitt."""
def __init__(self, sensor_name, key, system, stype):
"""Initialize."""
self.name = sensor_name
self.key = key
self.value = None
self.system = system
self.stype = stype
self.lastupd = 0
self.lastupd_m = 0

def get_value(self):
"""Get the sensor value."""
return self.value

def set_value(self, value):
"""Set the sensor value."""
self.value = value

def get_system(self):
"""Get the system."""
return self.system

def get_stype(self):
"""Get the sensor type."""
return self.stype

def get_name(self):
"""Get the sensor name."""
return self.name

def get_key(self):
"""Get the sensor key."""
return self.key

def set_lastupd(self, value):
"""Set the last update time on this sensor."""
self.lastupd = value

def get_lastupd(self):
"""Get the last update time of this sensor."""
return self.lastupd

def set_lastupd_m(self, value):
"""Set the last update monotonic time on this sensor."""
self.lastupd_m = value

def get_lastupd_m(self):
"""Get the last update monotonic time of this sensor."""
return self.lastupd_m


class EcoWittListener:
def __init__(self, port=ECOWITT_LISTEN_PORT):
# API Constants
Expand All @@ -31,6 +91,26 @@ def __init__(self, port=ECOWITT_LISTEN_PORT):
self.log = logging.getLogger(__name__)
self.lastupd = 0
self.windchill_type = WINDCHILL_HYBRID
self.new_sensor_cb = None

# storage
self._station_type = "Unknown"
self._station_freq = "Unknown"
self._station_model = "Unknown"
self._mac_addr = None

self.data_ready = False
self.sensors = []
self.known_sensor_keys = []

def int_new_sensor_cb(self):
"""Internal new sensor callback
binds to self.new_sensor_cb
"""
if self.new_sensor_cb is None:
return
self.new_sensor_cb()

def set_windchill(self, wind):
"""Set a windchill mode, [012]."""
Expand All @@ -53,7 +133,7 @@ def get_dew_point_c(self, t_air_c, rel_humidity):
"""
A = 17.27
B = 237.7
alpha = ((A * t_air_c) / (B + t_air_c)) + math.log(rel_humidity/100.0)
alpha = ((A * t_air_c) / (B + t_air_c)) + math.log(rel_humidity / 100.0)
return round((B * alpha) / (A - alpha), 2)

def _ftoc(self, f):
Expand Down Expand Up @@ -117,7 +197,7 @@ def convert_units(self, data):
# lightning
if "lightning_time" in data:
if (data["lightning_time"] is not None and
data["lightning_time"] != ''):
data["lightning_time"] != ''):
data["lightning_time"] = int(data["lightning_time"])
if "lightning_num" in data:
data["lightning_num"] = int(data["lightning_num"])
Expand Down Expand Up @@ -294,6 +374,32 @@ def convert_units(self, data):

return(data)

def find_sensor(self, key):
for sensor in self.sensors:
if sensor.get_key() == key:
return sensor
return None

def parse_ws_data(self, weather_data):
for sensor in weather_data.keys():
sensor_dev = self.find_sensor(sensor)
if sensor_dev is None:
# we have a new sensor
if sensor not in SENSOR_MAP:
self.log.warning("Unhandled sensor type %s value %s, "
+ "file a PR.", sensor, weather_data[sensor])
continue
sensor_dev = EcoWittSensor(SENSOR_MAP[sensor][MAP_NAME],
sensor,
SENSOR_MAP[sensor][MAP_SYSTEM],
SENSOR_MAP[sensor][MAP_STYPE].name)
self.sensors.append(sensor_dev)
self.int_new_sensor_cb()

sensor_dev.set_value(weather_data[sensor])
sensor_dev.set_lastupd(time.time())
sensor_dev.set_lastupd_m(time.monotonic())

async def handler(self, request: web.BaseRequest):
if (request.method == 'POST'):
data = await request.post()
Expand All @@ -305,6 +411,7 @@ async def handler(self, request: web.BaseRequest):
self.last_values = weather_data.copy()
self.data_valid = True
self.lastupd = time.time()
self.parse_ws_data(weather_data)
for rl in self.r_listeners:
try:
await rl(weather_data)
Expand Down Expand Up @@ -343,3 +450,26 @@ async def start(self):
self.log.error("Exiting listener {0}".format(str(e)))
finally:
loop.close()

# Accessor functions
def list_sensor_keys(self):
"""List all available sensors by key."""
sensor_list = []
for sensor in self.sensors:
sensor_list.append(sensor.get_key())
return sensor_list

def list_sensor_keys_by_type(self, stype):
"""List all available sensors of a given type."""
sensor_list = []
for sensor in self.sensors:
if sensor.get_stype() == stype:
sensor_list.append(sensor.get_key())
return sensor_list

def get_sensor_value_by_key(self, key):
"""Find the sensor named key and return its value."""
dev = self.find_sensor(key)
if dev is None:
return None
return dev.get_value()
4 changes: 4 additions & 0 deletions pyecowitt/fake_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ def usage():
host = sys.argv[1]
port = sys.argv[2]

# add a sensor
if len(sys.argv) > 3 and sys.argv[3] == 'add':
paramset_b['humidity2'] = 21

print("Connecting to host {0} on port {0}".format(host, port))
conn = http.client.HTTPConnection(host, port)
headers = {'Content-type': 'application/x-www-form-urlencoded'}
Expand Down
Loading

0 comments on commit 86439f5

Please sign in to comment.