From ee974ef41ab048c85a13c8bfc0f3fc9c6bf2ab35 Mon Sep 17 00:00:00 2001 From: mchlburton Date: Tue, 5 Sep 2017 14:30:40 -0400 Subject: [PATCH 1/4] awair API without dashboard view --- DeviceAPI/API_AwairSensor.py | 102 ++++++++++++++++++++++++++++ bemoss_lib/utils/BEMOSS_ONTOLOGY.py | 13 ++++ settings.py | 3 + 3 files changed, 118 insertions(+) create mode 100644 DeviceAPI/API_AwairSensor.py diff --git a/DeviceAPI/API_AwairSensor.py b/DeviceAPI/API_AwairSensor.py new file mode 100644 index 0000000..464e51c --- /dev/null +++ b/DeviceAPI/API_AwairSensor.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- +from __future__ import division +from bemoss_lib.utils.BEMOSS_ONTOLOGY import BEMOSS_ONTOLOGY +from DeviceAPI.BaseAPI import baseAPI +from settings import AWAIR_TOKEN +import requests +import urllib2 +import datetime +import json +debug = False + +class API(baseAPI): + def __init__(self,**kwargs): + super(API, self).__init__(**kwargs) + self.set_variable('connection_renew_interval',6000) + self.device_supports_auto = False + self.auth_token = AWAIR_TOKEN + self.devices_url = 'https://beta-api.awair.is/v1/users/self/devices' + self._debug = False + + def API_info(self): + return [{'device_model' : 'Awair+', 'vendor_name' : 'Awair', 'communication' : 'WiFi', + 'device_type_id' : 1,'api_name': 'API_AwairSensor', 'authorizable': False, 'is_cloud_device' : True, + 'chart_template': 'charts/charts_thermostat.html'}] + + def dashboard_view(self): + return + + def ontology(self): + return {"co2":BEMOSS_ONTOLOGY.CO2,"dust":BEMOSS_ONTOLOGY.DUST, + "temperature":BEMOSS_ONTOLOGY.TEMPERATURE,"VOC":BEMOSS_ONTOLOGY.VOC, + "humidity":BEMOSS_ONTOLOGY.RELATIVE_HUMIDITY} + + def discover(self): + head_auth = {'Authorization' : self.auth_token} + try: + devices_req = requests.get(self.devices_url, headers = head_auth, timeout=10) + except Exception as er: + print er + pass + + discovered_devices = list() + + if devices_req is not None: + devices_json = devices_req.json() + for device in devices_json['data']: + discovered_devices.append(str(device['device_id'])) + + return discovered_devices + + def getModelVendor(self,address): + return {'model': 'Awair+', 'vendor': 'Awair'} + + # GET Open the URL and read the data + def getDataFromDevice(self): + token = self.get_variable('token') + awair_id = self.get_variable('address') + print awair_id + + head_auth = {'Authorization': token} + + device_url = 'https://beta-api.awair.is/v1/devices/' + str(awair_id) + '/events/15min-avg' + start = (datetime.datetime.now()-datetime.timedelta(minutes=15)).isoformat() + end = datetime.datetime.now().isoformat() + timespan = {'from': start, 'to': end} + try: + data_req = requests.get(device_url,headers = head_auth, params = timespan) + + data_json = data_req.json() + print data_json + data_list = [] + for row in data_json['data']: + data = row['sensor'].values() + time = row['timestamp'] + + self.set_variable('dust', data[0]) + self.set_variable('co2', data[1]) + self.set_variable('humidity', data[2]) + self.set_variable('temperature', data[3]) + self.set_variable('voc', data[4]) + + except Exception as er: + print er + + + +# This main method will not be executed when this class is used as a module +def main(): + # Step1: create an object with initialized data from DeviceDiscovery Agent + # requirements for instantiation1. model, 2.type, 3.api, 4. address + CT50Thermostat = API(model='CT50',agent_id='wifithermostat1',api='API1',address='http://192.168.10.166') + print("{0}agent is initialzed for {1} using API={2} at {3}".format(CT50Thermostat.get_variable('agent_id'),CT50Thermostat.get_variable('model'),CT50Thermostat.get_variable('api'),CT50Thermostat.get_variable('address'))) + #CT50Thermostat.getDeviceModel() + # CT50Thermostat.getDeviceSchedule() + # CT50Thermostat.setDeviceStatus({"thermostat_mode":"COOL","cool_setpoint":78}) + CT50Thermostat.getDeviceStatus() + #CT50Thermostat.identifyDevice() + # scheduleData = {'Enabled': True, 'monday':[['Morning', 50, 83, 80],['Day',480, 72, 82],['Evening',960, 71, 84],['Night',1000, 69, 72]], 'tuesday':[['Morning', 360 , 70, 80],['Day',480, 72, 82],['Evening',960, 71, 84],['Night',1000, 69, 72]],'wednesday':[['Morning', 300 , 70, 80],['Day',480, 72, 82],['Evening',960, 71, 84],['Night',1000, 69, 72]],'thursday':[['Morning', 360 , 70, 80],['Day',480, 72, 82],['Evening',960, 71, 84],['Night',1000, 69, 72]],'friday':[['Morning', 360 , 70, 80],['Day',480, 72, 82],['Evening',960, 71, 84],['Night',1000, 69, 72]],'saturday':[['Morning', 360 , 70, 80],['Day',480, 72, 82],['Evening',960, 71, 84],['Night',1000, 69, 72]],'sunday':[['Morning', 360 , 70, 80],['Day',480, 72, 82],['Evening',960, 71, 84],['Night',1000, 69, 72]],} + # CT50Thermostat.setDeviceSchedule(scheduleData) + # CT50Thermostat.discover() + +if __name__ == "__main__": main() \ No newline at end of file diff --git a/bemoss_lib/utils/BEMOSS_ONTOLOGY.py b/bemoss_lib/utils/BEMOSS_ONTOLOGY.py index 886fd6a..313896c 100644 --- a/bemoss_lib/utils/BEMOSS_ONTOLOGY.py +++ b/bemoss_lib/utils/BEMOSS_ONTOLOGY.py @@ -313,6 +313,19 @@ class BEMOSS_ONTOLOGY: ALTERNATE_NAMES = ['Carbondioxide'] SPOKEN_NAMES = ['carbon dioxide','carbon dioxide level'] + class VOC: + NAME = 'voc' + TYPE = 'float' + UNIT = 'ppb' + ALTERNATE_NAMES = ['VOC'] + SPOKEN_NAMES = ['volatile organic chemicals'] + + class DUST: + NAME = 'dust' + TYPE = 'float' + UNIT = 'ug/m^3' + ALTERNATE_NAMES = ['PM10'] + class NOISE: NAME = 'noise' TYPE = 'float' diff --git a/settings.py b/settings.py index 3188c06..b847df0 100644 --- a/settings.py +++ b/settings.py @@ -164,6 +164,9 @@ SECRET_KEY = 'b4nr@$=^2)_g!_vz-nm_1$_!!jfh&2yn$6#a9klqyh28g*vjl%' # Alexa Authentication PIN: ALEXA_KEY = '93712' +#Awair authentication token +AWAIR_TOKEN = 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNTUxOSJ9.3YE0APseF-aLMcjTMSbN4bHgE--ZgcuWBEXVs-5TTO4' + #Weather Underground Key WUNDERGROUND_KEY = 'underground-key' -- GitLab From 24463c520277b7d883eb5ceed0ce792a4ed17f5d Mon Sep 17 00:00:00 2001 From: mchlburton Date: Thu, 7 Sep 2017 17:43:57 -0400 Subject: [PATCH 2/4] update awair API_info and discover function --- DeviceAPI/API_AwairSensor.py | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/DeviceAPI/API_AwairSensor.py b/DeviceAPI/API_AwairSensor.py index 464e51c..cd7fe13 100644 --- a/DeviceAPI/API_AwairSensor.py +++ b/DeviceAPI/API_AwairSensor.py @@ -14,50 +14,51 @@ class API(baseAPI): super(API, self).__init__(**kwargs) self.set_variable('connection_renew_interval',6000) self.device_supports_auto = False - self.auth_token = AWAIR_TOKEN self.devices_url = 'https://beta-api.awair.is/v1/users/self/devices' self._debug = False def API_info(self): return [{'device_model' : 'Awair+', 'vendor_name' : 'Awair', 'communication' : 'WiFi', - 'device_type_id' : 1,'api_name': 'API_AwairSensor', 'authorizable': False, 'is_cloud_device' : True, - 'chart_template': 'charts/charts_thermostat.html'}] + 'device_type_id' : 4,'api_name': 'API_AwairSensor', 'html_template': '---', 'agent_type': 'basic', + 'identifiable': False, 'authorizable': False, 'is_cloud_device' : True, + 'schedule_weekday_period': '4', 'schedule_weekend_period': '4', + 'allow_schedule_period_delete': 'False', 'chart_template': 'charts/charts_thermostat.html'}] def dashboard_view(self): - return + return {"top": {"type": "number", "value": "co2"}, "center": {"type": "number", "value": "voc"}, + "bottom": {"type": "number", "value": "dust"}} def ontology(self): return {"co2":BEMOSS_ONTOLOGY.CO2,"dust":BEMOSS_ONTOLOGY.DUST, "temperature":BEMOSS_ONTOLOGY.TEMPERATURE,"VOC":BEMOSS_ONTOLOGY.VOC, "humidity":BEMOSS_ONTOLOGY.RELATIVE_HUMIDITY} - def discover(self): - head_auth = {'Authorization' : self.auth_token} + def discover(self, username, password): + self.token = password + head_auth = {'Authorization' : self.token} try: devices_req = requests.get(self.devices_url, headers = head_auth, timeout=10) except Exception as er: print er - pass + raise discovered_devices = list() if devices_req is not None: devices_json = devices_req.json() - for device in devices_json['data']: - discovered_devices.append(str(device['device_id'])) + model_vendor = self.getModelVendor() + discovered_devices = [{'address': str(device['device_id']), 'macaddress': str(device['device_id'])} for device in devices_json['data']] + discovered_devices = [device.update(model_vendor) for device in discovered_devices] return discovered_devices - def getModelVendor(self,address): + def getModelVendor(self): return {'model': 'Awair+', 'vendor': 'Awair'} # GET Open the URL and read the data def getDataFromDevice(self): - token = self.get_variable('token') awair_id = self.get_variable('address') - print awair_id - - head_auth = {'Authorization': token} + head_auth = {'Authorization': self.token} device_url = 'https://beta-api.awair.is/v1/devices/' + str(awair_id) + '/events/15min-avg' start = (datetime.datetime.now()-datetime.timedelta(minutes=15)).isoformat() @@ -67,11 +68,8 @@ class API(baseAPI): data_req = requests.get(device_url,headers = head_auth, params = timespan) data_json = data_req.json() - print data_json - data_list = [] for row in data_json['data']: data = row['sensor'].values() - time = row['timestamp'] self.set_variable('dust', data[0]) self.set_variable('co2', data[1]) -- GitLab From 053da5236a64482c6067d8a7dbd0719330bd4d1b Mon Sep 17 00:00:00 2001 From: mchlburton Date: Thu, 21 Sep 2017 11:49:51 -0400 Subject: [PATCH 3/4] changed passwords_manager table to accept larger web_ui inputs; awairAPI properly parses data --- DeviceAPI/API_AwairSensor.py | 18 +++++++++++------- Web_Server/webapps/discovery/models.py | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/DeviceAPI/API_AwairSensor.py b/DeviceAPI/API_AwairSensor.py index cd7fe13..94ec95f 100644 --- a/DeviceAPI/API_AwairSensor.py +++ b/DeviceAPI/API_AwairSensor.py @@ -7,7 +7,7 @@ import requests import urllib2 import datetime import json -debug = False +debug = True class API(baseAPI): def __init__(self,**kwargs): @@ -15,11 +15,11 @@ class API(baseAPI): self.set_variable('connection_renew_interval',6000) self.device_supports_auto = False self.devices_url = 'https://beta-api.awair.is/v1/users/self/devices' - self._debug = False + self._debug = True def API_info(self): return [{'device_model' : 'Awair+', 'vendor_name' : 'Awair', 'communication' : 'WiFi', - 'device_type_id' : 4,'api_name': 'API_AwairSensor', 'html_template': '---', 'agent_type': 'basic', + 'device_type_id' : 4,'api_name': 'API_AwairSensor', 'html_template': '---', 'agent_type': 'BasicAgent', 'identifiable': False, 'authorizable': False, 'is_cloud_device' : True, 'schedule_weekday_period': '4', 'schedule_weekend_period': '4', 'allow_schedule_period_delete': 'False', 'chart_template': 'charts/charts_thermostat.html'}] @@ -47,8 +47,12 @@ class API(baseAPI): if devices_req is not None: devices_json = devices_req.json() model_vendor = self.getModelVendor() - discovered_devices = [{'address': str(device['device_id']), 'macaddress': str(device['device_id'])} for device in devices_json['data']] - discovered_devices = [device.update(model_vendor) for device in discovered_devices] + discovered_devices = [{'address': str(device['device_id']), 'mac': str(device['device_id'])} for device in devices_json['data']] + for device in discovered_devices: + device.update(model_vendor) + + if self._debug: + print discovered_devices return discovered_devices @@ -58,7 +62,7 @@ class API(baseAPI): # GET Open the URL and read the data def getDataFromDevice(self): awair_id = self.get_variable('address') - head_auth = {'Authorization': self.token} + head_auth = {'Authorization': self.get_variable('password')} device_url = 'https://beta-api.awair.is/v1/devices/' + str(awair_id) + '/events/15min-avg' start = (datetime.datetime.now()-datetime.timedelta(minutes=15)).isoformat() @@ -74,7 +78,7 @@ class API(baseAPI): self.set_variable('dust', data[0]) self.set_variable('co2', data[1]) self.set_variable('humidity', data[2]) - self.set_variable('temperature', data[3]) + self.set_variable('temperature', data[3]*1.8+32) #convert to fahrenheit self.set_variable('voc', data[4]) except Exception as er: diff --git a/Web_Server/webapps/discovery/models.py b/Web_Server/webapps/discovery/models.py index 5b8b923..aa196cc 100644 --- a/Web_Server/webapps/discovery/models.py +++ b/Web_Server/webapps/discovery/models.py @@ -59,7 +59,7 @@ kwargs = {'subscribe_address': __.SUB_SOCKET, class PasswordsManager(models.Model): device_model = models.ForeignKey(SupportedDevices, db_column="device_model") username = models.CharField(max_length=128) - password = models.CharField(_('password'), max_length=128) + password = models.CharField(_('password'), max_length=256) last_modified = models.DateTimeField() class Meta: -- GitLab From d375f1cc671967410b28593e4fc86fa666adc6e3 Mon Sep 17 00:00:00 2001 From: mchlburton Date: Thu, 21 Sep 2017 17:40:26 -0400 Subject: [PATCH 4/4] verbose exceptions;added TODO;API main for testing --- DeviceAPI/API_AwairSensor.py | 27 +++++++++++---------------- settings.py | 6 ------ 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/DeviceAPI/API_AwairSensor.py b/DeviceAPI/API_AwairSensor.py index 94ec95f..3bc5883 100644 --- a/DeviceAPI/API_AwairSensor.py +++ b/DeviceAPI/API_AwairSensor.py @@ -7,7 +7,6 @@ import requests import urllib2 import datetime import json -debug = True class API(baseAPI): def __init__(self,**kwargs): @@ -15,14 +14,15 @@ class API(baseAPI): self.set_variable('connection_renew_interval',6000) self.device_supports_auto = False self.devices_url = 'https://beta-api.awair.is/v1/users/self/devices' - self._debug = True + self._debug = False def API_info(self): + #TODO: create chart_template and html_template for awair return [{'device_model' : 'Awair+', 'vendor_name' : 'Awair', 'communication' : 'WiFi', 'device_type_id' : 4,'api_name': 'API_AwairSensor', 'html_template': '---', 'agent_type': 'BasicAgent', 'identifiable': False, 'authorizable': False, 'is_cloud_device' : True, 'schedule_weekday_period': '4', 'schedule_weekend_period': '4', - 'allow_schedule_period_delete': 'False', 'chart_template': 'charts/charts_thermostat.html'}] + 'allow_schedule_period_delete': False, 'chart_template': '---'}] def dashboard_view(self): return {"top": {"type": "number", "value": "co2"}, "center": {"type": "number", "value": "voc"}, @@ -36,13 +36,13 @@ class API(baseAPI): def discover(self, username, password): self.token = password head_auth = {'Authorization' : self.token} + discovered_devices = list() try: devices_req = requests.get(self.devices_url, headers = head_auth, timeout=10) except Exception as er: + print "AwairSensor API fails HTTP request" print er - raise - - discovered_devices = list() + return discovered_devices if devices_req is not None: devices_json = devices_req.json() @@ -82,6 +82,7 @@ class API(baseAPI): self.set_variable('voc', data[4]) except Exception as er: + print "AwairAPI could not get device data" print er @@ -90,15 +91,9 @@ class API(baseAPI): def main(): # Step1: create an object with initialized data from DeviceDiscovery Agent # requirements for instantiation1. model, 2.type, 3.api, 4. address - CT50Thermostat = API(model='CT50',agent_id='wifithermostat1',api='API1',address='http://192.168.10.166') - print("{0}agent is initialzed for {1} using API={2} at {3}".format(CT50Thermostat.get_variable('agent_id'),CT50Thermostat.get_variable('model'),CT50Thermostat.get_variable('api'),CT50Thermostat.get_variable('address'))) - #CT50Thermostat.getDeviceModel() - # CT50Thermostat.getDeviceSchedule() - # CT50Thermostat.setDeviceStatus({"thermostat_mode":"COOL","cool_setpoint":78}) - CT50Thermostat.getDeviceStatus() - #CT50Thermostat.identifyDevice() - # scheduleData = {'Enabled': True, 'monday':[['Morning', 50, 83, 80],['Day',480, 72, 82],['Evening',960, 71, 84],['Night',1000, 69, 72]], 'tuesday':[['Morning', 360 , 70, 80],['Day',480, 72, 82],['Evening',960, 71, 84],['Night',1000, 69, 72]],'wednesday':[['Morning', 300 , 70, 80],['Day',480, 72, 82],['Evening',960, 71, 84],['Night',1000, 69, 72]],'thursday':[['Morning', 360 , 70, 80],['Day',480, 72, 82],['Evening',960, 71, 84],['Night',1000, 69, 72]],'friday':[['Morning', 360 , 70, 80],['Day',480, 72, 82],['Evening',960, 71, 84],['Night',1000, 69, 72]],'saturday':[['Morning', 360 , 70, 80],['Day',480, 72, 82],['Evening',960, 71, 84],['Night',1000, 69, 72]],'sunday':[['Morning', 360 , 70, 80],['Day',480, 72, 82],['Evening',960, 71, 84],['Night',1000, 69, 72]],} - # CT50Thermostat.setDeviceSchedule(scheduleData) - # CT50Thermostat.discover() + Awair = API(model='Awair+',agent_id='iaqsensor',api='API_AwairSensor',password='Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNTUxOSJ9.3YE0APseF-aLMcjTMSbN4bHgE--ZgcuWBEXVs-5TTO4') + print("{0}agent is initialzed for {1} using API={2}".format(Awair.get_variable('agent_id'),Awair.get_variable('model'),Awair.get_variable('api'))) + #Awair.getModelVendor() + Awair.getDeviceStatus() if __name__ == "__main__": main() \ No newline at end of file diff --git a/settings.py b/settings.py index b847df0..b63755c 100644 --- a/settings.py +++ b/settings.py @@ -161,12 +161,6 @@ LANGUAGE_CODE = 'en-us' # Make this unique, and don't share it with anybody. SECRET_KEY = 'b4nr@$=^2)_g!_vz-nm_1$_!!jfh&2yn$6#a9klqyh28g*vjl%' -# Alexa Authentication PIN: -ALEXA_KEY = '93712' - -#Awair authentication token -AWAIR_TOKEN = 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNTUxOSJ9.3YE0APseF-aLMcjTMSbN4bHgE--ZgcuWBEXVs-5TTO4' - #Weather Underground Key WUNDERGROUND_KEY = 'underground-key' -- GitLab