domotique:retro-ingenierie_d_une_station_meteo
Différences
Ci-dessous, les différences entre deux révisions de la page.
| Prochaine révision | Révision précédente | ||
| domotique:retro-ingenierie_d_une_station_meteo [03/08/2019 18:42] – créée antoineve | domotique:retro-ingenierie_d_une_station_meteo [20/10/2019 15:22] (Version actuelle) – Alecto antoineve | ||
|---|---|---|---|
| Ligne 1: | Ligne 1: | ||
| - | //TL;DR// : Le code est disponible sur GitHub : https:// | + | ~~DISCUSSION~~ |
| - | ====== Le signal radio ====== | + | {{ : |
| + | |||
| + | ====== Rétro-ingénierie d'une station météo ====== | ||
| + | |||
| + | Cette station météo, "Otio WH5100" | ||
| + | |||
| + | //TL;DR// : Le code est disponible sur mon repo git : https:// | ||
| + | |||
| + | ===== Le signal radio ===== | ||
| Pour recevoir les signaux de la station météo, j' | Pour recevoir les signaux de la station météo, j' | ||
| Ligne 12: | Ligne 20: | ||
| Voici un exemple des données reçues : | Voici un exemple des données reçues : | ||
| - | <code bash-session> | + | <code bash-session |
| $ rtl_433 -f 868292000 -q -A | $ rtl_433 -f 868292000 -q -A | ||
| Found Rafael Micro R820T tuner | Found Rafael Micro R820T tuner | ||
| Ligne 42: | Ligne 50: | ||
| User cancel, exiting... | User cancel, exiting... | ||
| + | </ | ||
| + | |||
| + | La ligne qui nous interresse ici est '' | ||
| + | |||
| + | ===== Analyse ===== | ||
| + | |||
| + | Vient ensuite le moment d' | ||
| + | Pour cela, j'ai laissé tourner l' | ||
| + | J'ai ainsi pu voir quelles parties de la chaîne se modifiaient dans la journée. | ||
| + | Pour une mieux visualiser ces données, j'ai écrit un script python utilisant pylab et numpy. | ||
| + | Ce script prend en argument le fichier écrit par rtl_433 et affiche un graphique. | ||
| + | |||
| + | <file python meteo_graph.py> | ||
| + | # | ||
| + | |||
| + | from sys import argv | ||
| + | from pylab import * | ||
| + | import numpy as np | ||
| + | |||
| + | data_file = argv[1] | ||
| + | |||
| + | |||
| + | def col2array(dico, | ||
| + | temp_liste = list() | ||
| + | for line in dico: | ||
| + | temp_liste.append(int(dico[line][col], | ||
| + | return(np.array(temp_liste)) | ||
| + | |||
| + | |||
| + | with open(data_file, | ||
| + | data = data.read().splitlines() | ||
| + | data_dict = {} | ||
| + | count = 0 | ||
| + | for line in data: | ||
| + | if "[00] {79}" in line: | ||
| + | data_dict.update({count: | ||
| + | count += 1 | ||
| + | x = np.array(list(data_dict.keys())) | ||
| + | y0 = col2array(data_dict, | ||
| + | y1 = col2array(data_dict, | ||
| + | y2 = col2array(data_dict, | ||
| + | y3 = col2array(data_dict, | ||
| + | y4 = col2array(data_dict, | ||
| + | y5 = col2array(data_dict, | ||
| + | y6 = col2array(data_dict, | ||
| + | y7 = col2array(data_dict, | ||
| + | y8 = col2array(data_dict, | ||
| + | y9 = col2array(data_dict, | ||
| + | |||
| + | figure(figsize=(21, | ||
| + | # plot(x, y0, label=" | ||
| + | # plot(x, y1, label=" | ||
| + | plot(x, y2, label=" | ||
| + | print(' | ||
| + | plot(x, y3, label=" | ||
| + | print(' | ||
| + | plot(x, y4, label=" | ||
| + | print(' | ||
| + | plot(x, y5, label=" | ||
| + | plot(x, y6, label=" | ||
| + | plot(x, y7, label=" | ||
| + | plot(x, y8, label=" | ||
| + | # plot(x, y9, label=" | ||
| + | legend(loc=' | ||
| + | # savefig("/ | ||
| + | show() | ||
| + | close(' | ||
| + | </ | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | J'ai ensuite rapproché les relevés bruts avec les données affichées sur le terminal météo fourni. | ||
| + | Après avoir un peu tâtonné, l' | ||
| + | Pour cette analyse numérique, je vais faire de la [[https:// | ||
| + | |||
| + | Avec python, c'est la fonction // | ||
| + | |||
| + | < | ||
| + | linregress(x, | ||
| + | Calculate a linear least-squares regression for two sets of measurements. | ||
| + | |||
| + | Parameters | ||
| + | ---------- | ||
| + | x, y : array_like | ||
| + | Two sets of measurements. | ||
| + | If only x is given (and y=None), then it must be a two-dimensional | ||
| + | array where one dimension has length 2. The two sets of measurements | ||
| + | are then found by splitting the array along the length-2 dimension. | ||
| + | |||
| + | Returns | ||
| + | ------- | ||
| + | slope : float | ||
| + | slope of the regression line | ||
| + | intercept : float | ||
| + | intercept of the regression line | ||
| + | rvalue : float | ||
| + | | ||
| + | pvalue : float | ||
| + | two-sided p-value for a hypothesis test whose null hypothesis is | ||
| + | that the slope is zero. | ||
| + | stderr : float | ||
| + | Standard error of the estimated gradient. | ||
| + | </ | ||
| + | |||
| + | ==== Température ==== | ||
| + | Pour la température, | ||
| + | (e.g. '' | ||
| + | L' | ||
| + | |||
| + | Régression linéaire : | ||
| + | |||
| + | <code pycon> | ||
| + | >>> | ||
| + | >>> | ||
| + | >>> | ||
| + | >>> | ||
| + | >>> | ||
| + | (0.050000000000000031, | ||
| + | >>> | ||
| + | 0.0 | ||
| + | >>> | ||
| + | </ | ||
| + | |||
| + | On a donc : f(x) = 0,05 * x − 1268,8. Avec une erreur standard nulle, ce qui signifie que la formule « tombe juste » | ||
| + | (Si on trace la courbe à partir de la formule, elle passe parfaitement par tous les points relevés). | ||
| + | |||
| + | En python : | ||
| + | |||
| + | <code pycon> | ||
| + | >>> | ||
| + | ... return round((0.05*data-1268.8), | ||
| + | ... | ||
| + | >>> | ||
| + | 17.0 | ||
| + | </ | ||
| + | |||
| + | J'ai également remarqué que l' | ||
| + | permettant d' | ||
| + | |||
| + | ==== Humidité ==== | ||
| + | |||
| + | Pour l' | ||
| + | On voit bien sur la courbe des relevés la relation qu'ont la température et l' | ||
| + | L' | ||
| + | La relation est donc très simple : y = 0.5 * x. | ||
| + | C'est à dire que la valeur de l' | ||
| + | |||
| + | En python : | ||
| + | |||
| + | <code pycon> | ||
| + | >>> | ||
| + | | ||
| + | ... | ||
| + | >>> | ||
| + | 94 | ||
| + | </ | ||
| + | |||
| + | ==== Anémomètre ==== | ||
| + | |||
| + | La station météo renvoie deux paramètres pour le vent : une moyenne (ou médiane ?) | ||
| + | et le maximum (ce qui correspond aux rafales). | ||
| + | Ceux-ci sont portés sur les octets 6 et 7. | ||
| + | L' | ||
| + | |||
| + | <code pycon> | ||
| + | >>> | ||
| + | >>> | ||
| + | >>> | ||
| + | >>> | ||
| + | >>> | ||
| + | (0.61264343715451175, | ||
| + | >>> | ||
| + | 0.0009343564466014815 | ||
| + | >>> | ||
| + | </ | ||
| + | |||
| + | J'ai essayé avec les différentes configuration : km/h, mph, knots (nœuds), ... | ||
| + | Jamais d' | ||
| + | Certainement une erreur à cause d' | ||
| + | |||
| + | La fonction est donc : | ||
| + | |||
| + | <code pycon> | ||
| + | >>> | ||
| + | ... return round((0.61264343715451175*data-0.018142655636458116), | ||
| + | ... | ||
| + | >>> | ||
| + | 55.1 | ||
| + | </ | ||
| + | |||
| + | ==== Pluviomètre ==== | ||
| + | Pour le pluviomètre, | ||
| + | il faut ajouter 0,3 mm de pluie. La donnée est codée sur 1 octet, le 8ème de la transmission, | ||
| + | Il faut pouvoir gérer cette situation. Pour plus de facilité, je stocke la valeur dans un fichier temporaire. | ||
| + | |||
| + | <code python> | ||
| + | def rain(raw): | ||
| + | | ||
| + | try: | ||
| + | with open("/ | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | if old_rain is None: | ||
| + | with open("/ | ||
| + | | ||
| + | | ||
| + | if current > old_rain: | ||
| + | res = round(float(current-old_rain)*0.3, | ||
| + | with open("/ | ||
| + | | ||
| + | else: | ||
| + | if (current+255)-old_rain < 254: | ||
| + | res = round(float((current+255)-old_rain)*0.3, | ||
| + | with open("/ | ||
| + | | ||
| + | else: | ||
| + | res = 0 | ||
| + | | ||
| </ | </ | ||
domotique/retro-ingenierie_d_une_station_meteo.1564857731.txt · Dernière modification : de antoineve
