Skip to content
Snippets Groups Projects
Commit f3009d37 authored by jkerdreu's avatar jkerdreu
Browse files

Initial backport to official svn


git-svn-id: https://redmine.imt-atlantique.fr/svn/xaal/code/Python/trunk@2014 b32b6428-25c9-4566-ad07-03861ab6144f
parent 01efe829
Branches
No related tags found
No related merge requests found
#I am supposed you have the environment of xaal on your computer.
#if not, look at this reference:
# https://redmine-df.telecom-bretagne.eu/projects/projet_dev_s2_30/repository/entry/trunk/README.rst
# any problem of netatmo gateway, please contect: caifeng.bao@imt-atlantique.net
#
#
# wind,rain gouge, additional indoor
# https://www.netatmo.com/en-US/product/weather/weatherstation/accessories#module
#
# https://dev.netatmo.com/en-US/resources/technical/reference/weather/getstationsdata
#========================================================================================================
#some modifications
#========================================================================================================
#in the gw.py, we need to import xaal.lib, so, you should make sure xaal.lib in your $PYTHONPATH
#(you can do export PYTHONPATH="your path of xaal.lib")
#or, simply copy the xaal.lib to yor gw.py directory
#========================================================================================================
#some units
#========================================================================================================
#-Metric---------------------------Units
#-Pressure-------------------------mbar
#-Temperature----------------------°C
#-CO2------------------------------ppm
#-Humidity-------------------------%
#-Noise----------------------------dB
# for more information, please go to this website :
# https://dev.netatmo.com/en-US/resources/technical/reference/weather
#=========================================================================================================
# all the parameter comes from Netatmo Cloud
# this is dashboard_data of your netatmo weather station:
# https://dev.netatmo.com/en-US/resources/technical/reference/weather
# (If you want to use our code and do some modification, please read the dashboard_data clearly,
# it will help you a lot)
#=========================================================================================================
#
#first,create the configuration files in your home directory:
$cd /home/cassiel/xAAL/trunk/devices/weather/NetatmoWeatherStation
$cp xaal.netatmo.ini.sample ~/.xaal/xaal.netatmo.ini
$gedit ~/.xaal/xaal.netatmo.ini
#configure your xaal.netatmo.ini file
#if you don't understand the parametres in this file,look at this reference:
# https://dev.netatmo.com/resources/technical/samplessdks/codesamples
#second, test your netatmo gatway
#before you start, you should make sure your netatmo weather station is connected to netatmo cloud
#that is to say, your netatmo weather station is working
#and your computer needs to be connected to the Internet
#lauch at the xaal monitor
$xaal-tail 0
#then, lauch at anther terminal
$cd /home/cassiel/xAAL/trunk/devices/weather/NetatmoWeatherStation/xaal/netatmo
$python3 gw.py
#you will get information like this:
#2018-03-29 03:26:40,844 - requests.packages.urllib3.connectionpool - INFO - Starting new HTTPS connection (1): api.netatmo.com
#2018-03-29 03:26:41,130 - requests.packages.urllib3.connectionpool - DEBUG - "POST /oauth2/token HTTP/1.1" 200 None
#Your access token is: 5a7b5176b4809d4dde8b58ca|8b632b6ab6a9ec4242a37a8641501193
#2018-03-29 03:26:41,144 - requests.packages.urllib3.connectionpool - INFO - Starting new HTTPS connection (1): api.netatmo.com
#2018-03-29 03:26:41,298 - requests.packages.urllib3.connectionpool - DEBUG - "POST /api/getstationsdata?device_id=70%3Aee%3A50%3A1f%3A56%3A60&access_token=5a7b5176b4809d4dde8b58ca%7C8b632b6ab6a9ec4242a37a8641501193 HTTP/1.1" 200 None
#2018-03-29 03:26:41,312 - xaal.lib.network - INFO - Connecting to 224.0.29.200:1235
#2018-03-29 03:26:41,347 - requests.packages.urllib3.connectionpool - INFO - Starting new HTTPS connection (1): api.netatmo.com
#2018-03-29 03:26:41,536 - requests.packages.urllib3.connectionpool - DEBUG - "POST /oauth2/token HTTP/1.1" 200 None
#Your access token is: 5a7b5176b4809d4dde8b58ca|8b632b6ab6a9ec4242a37a8641501193
#2018-03-29 03:26:41,542 - requests.packages.urllib3.connectionpool - INFO - Starting new HTTPS connection (1): api.netatmo.com
#2018-03-29 03:26:41,697 - requests.packages.urllib3.connectionpool - DEBUG - "POST /api/getstationsdata?device_id=70%3Aee%3A50%3A1f%3A56%3A60&access_token=5a7b5176b4809d4dde8b58ca%7C8b632b6ab6a9ec4242a37a8641501193 HTTP/1.1" 200 None
#2018-03-29 03:26:41,700 - xaal.lib.devices - DEBUG - Attr change temperature=22.2
#2018-03-29 03:26:41,700 - xaal.lib.devices - DEBUG - Attr change humidity=51
#2018-03-29 03:26:41,700 - xaal.lib.devices - DEBUG - Attr change pressure=1018.5
#2018-03-29 03:26:41,700 - xaal.lib.devices - DEBUG - Attr change co2=1193
#2018-03-29 03:26:41,700 - xaal.lib.devices - DEBUG - Attr change noise=38
#at the same time, you can see the action of xaal devices on monitor
#the output will like this:
#notify => attributes 3b96553a-32f0-11e8-9ecf-e0db55fb413a (noise_detector.basic) [] {'noise': 38}
#notify => attributes 3b96553a-32f0-11e8-9ecf-e0db55fb413a (air_quality.basic ) [] {'co2': 1193}
#notify => attributes 3b96553a-32f0-11e8-9ecf-e0db55fb413a (hygrometer.basic ) [] {'humidity': 51}
#notify => attributes 3b96553a-32f0-11e8-9ecf-e0db55fb413a (barometer.basic ) [] {'pressure': 1018.5}
#notify => attributes 3b96553a-32f0-11e8-9ecf-e0db55fb413a (thermometer.basic ) [] {'temperature': 22.2}
#and also, you can do this:
$ xaal-isalive
#you will recieve this information:
#2018-03-29 04:21:17,387 - xaal.lib.network - INFO - Connecting to 224.0.29.200:1235
#[dc950dda-32f7-11e8-9ecf-e0db55fb413a] Sending xAAL isAlive [any.any]
#======================================================================
#d983ae76-32f7-11e8-9ecf-e0db55fb413a : thermometer.basic
#d983ae77-32f7-11e8-9ecf-e0db55fb413a : hygrometer.basic
#d983ae78-32f7-11e8-9ecf-e0db55fb413a : barometer.basic
#d983ae79-32f7-11e8-9ecf-e0db55fb413a : air_quality.basic
#d983ae7a-32f7-11e8-9ecf-e0db55fb413a : noise_detector.basic
#d983ae7b-32f7-11e8-9ecf-e0db55fb413a : gateway.basic
======================================================================
from setuptools import setup,find_packages
with open('README.rst') as f:
long_description = f.read()
VERSION = "0.1"
setup(
name="xaal.netatmo",
version=VERSION,
license='GPL License',
author='Caifeng BAO',
author_email='caifeng.bao@imt-atlantique.fr',
url='https://dev.netatmo.com',
description=('Netatmo Weather Station'),
long_description=long_description,
classifiers=[
'Programming Language :: Python',
'Topic :: Software Development :: Libraries :: Python Modules',
],
keywords=['xaal', 'netatmo','weather','station'],
platforms='any',
packages=find_packages(),
include_package_data=True,
install_requires=[
'xaal.lib',
'requests',
'ujson',
]
)
[config]
grant_type = password
client_id = xxxxxxxxxxxxxxxxxxxx
client_secret = xxxxxxxxxxxxxxxxxx
password = xxxxxxxxxxxxxxxxx
username = xxxxxxxxxxxxxxxxx
scope = read_station
device_id = 70:ee:50:1f:56:60
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
from . import gateway
gateway.main()
from xaal.lib import Device,DeviceError
import platform
PACKAGE_NAME = "xaal.netatmo"
class NWS(object): # NWS: netatmo weather station
def __init__(self,base_addr,group,macId=None):
self.sensors=[]
self.base_addr=base_addr
self.group=group
self.macId=macId
def build_dev(self,dtype,addr):
dev = Device(dtype)
dev.devtype = dtype
dev.address = addr
dev.vendor_id = "NETATMO"
dev.product_id = "NetatmoWeatherStation"
dev.info = "%s@%s" % (PACKAGE_NAME,platform.node())
dev.url = "https://dev.netatmo.com/"
dev.version = 0.1
return dev
def new_sensor(self,sensor_type,sensor_attr,senor_addr,sensor_group):
s_type=sensor_type+".basic"
sensor = self.build_dev(s_type,senor_addr)
for attr in sensor_attr :
a=sensor.new_attribute(attr)
pass
sensor.group_id = sensor_group
return sensor
def update_sensor(self,sensor,sensor_attr,attr_value):
if isinstance(sensor,Device) :
attr=sensor.get_attribute(sensor_attr)
if attr :
attr.value=attr_value
else:
raise DeviceError("This sensor is invalid")
def new_sensors(self,sensors_type_list):
for i in range (len(sensors_type_list)) :
sensor_type=sensors_type_list[i]
sensor_attr=self.__get_sensor_attr(sensor_type)
sensor_addr= '%s%02x' % (self.base_addr[:-2],i+1)
sensor=self.new_sensor(sensor_type,sensor_attr,sensor_addr,self.group)
self.sensors.append(sensor)
def update_sensors(self,attr_value_dic):
for sensor in self.sensors :
for sensor_attr,attr_value in attr_value_dic.items():
self.update_sensor(sensor,sensor_attr,attr_value)
def __get_sensor_attr(self,sensor_type):
if sensor_type=="thermometer" :
return ["temperature"]
elif sensor_type=="hygrometer" :
return ["humidity"]
elif sensor_type=="barometer" :
return ["pressure"]
elif sensor_type=="co2meter" :
return ["co2"]
elif sensor_type=="soundmeter" :
return ["sound"]
elif sensor_type=="windmeter" :
return ["windstrength","windangle","guststrength","gustangle"]
elif sensor_type=="rainmeter" :
return ["rain"]
elif sensor_type=="radiometer" :
return ["radio_status"]
elif sensor_type=="wifimeter" :
return ["wifi_status"]
elif sensor_type=="batterymeter" :
return ["battery_level"]
else:
print("invalid sensor type !")
class NWSM(NWS): # NWSM: netatmo weather station module
def __init__(self,module_addr,module_group):
NWS.__init__(self,module_addr,module_group)
pass
def init_module(self,sensors_type_list):
self.new_sensors(sensors_type_list)
def update_module(self,attr_value_dic):
self.update_sensors(attr_value_dic)
"""
# test
def main():
try:
mainIndoor=NWSM('5d3cdc97-48b0-11e8-aaf2-e0db55fb413b','5d3cdc97-48b0-11e8-aaf2-e0db55fb413a')
print(str(mainIndoor))
s=["thermometer","hygrometer","barometer","co2meter","soundmeter","wifimeter"]
mainIndoor.init_module(s)
d={"temperature":10,
"humidity":20,
"pressure":30,
"co2":40,
"sound":50,
"wifi_status":100}
mainIndoor.update_module(d)
print(mainIndoor.sensors)
additionIndoor=NWSM('5d3cdc97-48b0-11e8-aaf2-e0db55fb413b','5d3cdc97-48b0-11e8-aaf2-e0db55fb413a')
print(str(additionIndoor))
s=["thermometer","hygrometer","co2meter","radiometer","batterymeter"]
additionIndoor.init_module(s)
d={"temperature":10,
"humidity":20,
"co2":40,
"radio_status":56,
"battery_level":100}
additionIndoor.update_module(d)
print(additionIndoor.sensors)
outdoor=NWSM('5d3cdc97-48b0-11e8-aaf2-e0db55fb413b','5d3cdc97-48b0-11e8-aaf2-e0db55fb413a')
print(str(outdoor))
s=["thermometer","hygrometer","radiometer","batterymeter"]
outdoor.init_module(s)
d={"temperature":10,
"humidity":20,
"radio_status":56,
"battery_level":100}
outdoor.update_module(d)
print(outdoor.sensors)
rainGouge=NWSM('5d3cdc97-48b0-11e8-aaf2-e0db55fb413b','5d3cdc97-48b0-11e8-aaf2-e0db55fb413a')
print(str(rainGouge))
s=["rainmeter","radiometer","batterymeter"]
rainGouge.init_module(s)
d={"rain":10,
"radio_status":56,
"battery_level":100}
rainGouge.update_module(d)
print(rainGouge.sensors)
windGouge=NWSM('5d3cdc97-48b0-11e8-aaf2-e0db55fb413b','5d3cdc97-48b0-11e8-aaf2-e0db55fb413a')
print(str(windGouge))
s=["windmeter","radiometer","batterymeter"]
windGouge.init_module(s)
d={"windstrength":10,
"windangle":20,
"guststrength":30,
"gustangle":40,
"radio_status":56,
"battery_level":100}
windGouge.update_module(d)
print(windGouge.sensors)
except KeyboardInterrupt:
print("Bye Bye..")
if __name__ == '__main__':
main()
"""
from xaal.lib import Engine,tools,config
import sys
#print(sys.path)
sys.path.append("./xaal/netatmo/")
from .nwsc import NWSC
from .nwscn import NWSCN
from .devices import *
PACKAGE_NAME = "xaal.netatmo"
logger = tools.get_logger(PACKAGE_NAME,'DEBUG')
RATE = 300 # update every 5 min
class GW:
def __init__(self,engine):
filename=tools.get_cfg_filename(PACKAGE_NAME)
self.cfg=tools.load_cfg_file(filename)
self.eng = engine
self.modules=[]
self.setup()
def setup(self):
# check config file
configfile=NWSC(self.cfg)
configfile.update_configfile()
# init modules
self.__init_modules()
# GW
base_addr = self.cfg['gateway']['base_addr']
nws=NWS(base_addr,group=None)
gw=nws.build_dev("gateway.basic",base_addr)
self.eng.add_device(gw)
# embedded
emb = gw.new_attribute('embedded',[]).value
for mod in self.modules :
for dev in mod.sensors:
self.eng.add_device(dev)
emb.append(dev.address)
# run the timer
self.eng.add_timer(self.update,RATE)
def update(self):
self.__readweatherstation()
print("update")
def __init_modules(self):
"""init all modules"""
devices=self.cfg["devices"]
for _id,value in devices.items():
group=value["group_addr"]
addr=value["base_addr"]
if value["type"]=="NAMain":
sensors_type=["thermometer","hygrometer","barometer","co2meter","soundmeter","wifimeter"]
elif value["type"]=="NAModule1": # addition outdoor
sensors_type=["thermometer","hygrometer","radiometer","batterymeter"]
elif value["type"]=="NAModule4": #additional indoor
sensors_type=["thermometer","hygrometer","co2meter","radiometer","batterymeter"]
elif value["type"]=="NAModule2": # additon wind gauge
sensors_type=["windmeter","radiometer","batterymeter"]
elif value["type"]=="NAModule3": # addition rain gauge
sensors_type=["rainmeter","radiometer","batterymeter"]
else:
print("invalid modules!!!")
module=NWSM(addr,group)
module.macId=_id
module.init_module(sensors_type)
self.modules.append(module)
def __update_modules(self,macId,attr):
for m in self.modules :
if m.macId == macId :
m.update_module(attr)
def __readweatherstation(self):
netatmo_connect=NWSCN(self.cfg)
netatmo_data= netatmo_connect.get_data()
main_indoor = netatmo_data["devices"][0] # dic
netatmo_modules= main_indoor["modules"] # list
try:# main indoor
print("starting netatmo gateway.......")
macId=main_indoor["_id"]
attr={"wifi_status": main_indoor["wifi_status"]}
data = main_indoor["dashboard_data"]
attr["temperature"]= data["Temperature"]
attr["humidity"]= data["Humidity"]
attr["pressure"]= data["Pressure"]
attr["co2"]= data["CO2"]
attr["sound"]= data["Noise"]
self.__update_modules(macId,attr)
except:
print("netatmo gateway failed !!! macId=%s"%macId)
else:
print("netatmo gateway succeed !!! macId=%s"%macId)
try: # update modules
print("update addition modules........")
for m in netatmo_modules :
macId=m["_id"]
attr={"radio_status": m["rf_status"],
"battery_level": m["battery_percent"]}
data =m['dashboard_data']
try : # update every module
if m["type"]=="NAModule1": # addition outdoor
attr["temperature"]= data["Temperature"]
attr["humidity"]= data["Humidity"]
elif m["type"]=="NAModule2": # additon wind gauge
# in API we can also get history of wind, here we don't
attr["windstrength"]= data["WindStrength"]
attr["windangle"]= data["WindAngle"]
attr["guststrength"]= data["GustStrength"]
attr["gustangle"]= data["GustAngle"]
elif m["type"]=="NAModule3" : # addition rain gauge
attr["rain"]= data["Rain"]
elif m["type"]=="NAModule4" : #additional indoor
attr["temperature"]= data["Temperature"]
attr["humidity"]= data["Humidity"]
attr["co2"]= data["CO2"]
else :
print("invalid netatmo module type !!!")
self.__update_modules(macId,attr)
except:
print("addition module update failed !!! macId=%s"%macId)
else:
print("addition module update succeeded !!! macId=%s"%macId)
except:
print("wrong modules !!!")
else:
print("update finished !!!")
###########################################################################################
def run():
eng = Engine()
log = GW(eng)
eng.run()
def main():
try:
run()
except KeyboardInterrupt:
print("Bye Bye..")
if __name__ == '__main__':
main()
from xaal.lib import tools
from configobj import ConfigObj
from .nwscn import NWSCN
class NWSC: # netatmo weather station config
def __init__(self,configfile):
self.configfile = configfile
def update_configfile(self):
if 'config' not in self.configfile:
print("invalid config file !!!")
if ('gateway' not in self.configfile)or('base_addr' not in self.configfile['gateway'])or(not tools.is_valid_addr(self.configfile['gateway']["base_addr"])):
self.configfile['gateway']={}
self.configfile['gateway']['base_addr']=tools.get_random_uuid()
if 'devices' not in self.configfile:
self.configfile['devices']={}
self.__update_devices()
self.configfile.write()
def __update_devices(self):
modules=self.__get_modules()
for i in range(len(modules)):
if modules[i][0] not in self.configfile['devices'] :
self.configfile['devices'][modules[i][0]]={}
self.configfile['devices'][modules[i][0]]['group_addr']=tools.get_random_uuid()
self.configfile['devices'][modules[i][0]]['base_addr']=tools.get_random_uuid()
self.configfile['devices'][modules[i][0]]['type']=modules[i][1]
self.configfile['devices'][modules[i][0]].inline_comments['type']=self.__get_comments(modules[i][1])
# check if all devices valid
list_macId=[]
for m in modules :
list_macId.append(m[0])
for k in self.configfile['devices'] :
if k not in list_macId :
self.configfile['devices'][k]['type']='NoneType'
self.configfile['devices'][k].inline_comments['type']=self.__get_comments('NoneType')
self.configfile['devices'].inline_comments[k]='This device is removed !!!'
def __get_modules(self): # get list of all modules,[MAC addr,'NetatmoType']
nwscn=NWSCN(self.configfile)
data=nwscn.get_data()
main_module=data['devices'][0]
m_type= main_module['type']
m_macId= main_module['_id']
modules=[[m_macId,m_type]]
m=main_module['modules']
for k in range(0,len(m)):
m_type=m[k]['type']
m_macId=m[k]['_id']
modules=modules+[[m_macId,m_type]]
return modules
def __get_comments(self,netatmo_type):
if netatmo_type=='NAMain':
return 'mainIndoor'
elif netatmo_type=='NAModule1':
return 'additionOutdoor'
elif netatmo_type=='NAModule2':
return 'additionWindGauge'
elif netatmo_type=='NAModule3':
return 'additionRainGauge'
elif netatmo_type=='NAModule4':
return 'additionIndoor'
else:
return 'invalid netatmo type !!!'
"""
# test
FILE_NAME="xaal.netatmo"
PACKAGE_NAME = "xaal.netatmo"
def main():
configfile = tools.load_cfg_or_die(PACKAGE_NAME)
config=NWSC(configfile)
config.update_configfile()
if __name__ == '__main__':
main()
"""
import requests
class NWSCN: # netatmo weather station connection
def __init__(self,configfile):
self.configfile = configfile
def get_token(self):
#fonction which get the token
""" connect to netatmo cloud, return access token """
##read config
cfg = self.configfile['config']
payload = {
'grant_type' : cfg['grant_type'],
'client_id' : cfg['client_id'],
'client_secret' : cfg['client_secret'],
'password' : cfg['password'],
'username' : cfg['username'],
'scope' : cfg['scope']
}
try:
response = requests.post("https://api.netatmo.com/oauth2/token", data=payload)
response.raise_for_status()
access_token=response.json()["access_token"]
#print("Your access token is:", access_token)
return access_token
except requests.exceptions.HTTPError as error:
print(error.response.status_code, error.response.text)
def get_data(self): #Fonction which get the information from netatmo API by using a token
token=self.get_token()
cfg = self.configfile['config']
params = {
'access_token': token ,
'device_id': cfg['device_id']
}
try:
response = requests.post("https://api.netatmo.com/api/getstationsdata", params=params)
response.raise_for_status()
data = response.json()["body"]
return data
except requests.exceptions.HTTPError as error:
print(error.response.status_code, error.response.text)
"""
# test
from xaal.lib import tools
from configobj import ConfigObj
FILE_NAME="xaal.netatmo"
PACKAGE_NAME = "xaal.netatmo"
logger = tools.get_logger(PACKAGE_NAME,'DEBUG')
def main():
configfile = tools.load_cfg_or_die(PACKAGE_NAME)
con=NWSCN(configfile)
token=con.get_token()
data=con.get_data()
print(str(token))
print(str(data))
if __name__ == '__main__':
main()
"""
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment