Format messages Sigfox de Arduino vers OpenWindMap
-
Bonjour.
Un arduino MKRFox1200,un anémomètre Davis (ceux de nos vielles balises FFVL), un petit panneau solaire et un accu et je me suis lancé.
Voici un début de programme qui fonctionnait avant que je me décourage et je voyais mes données arriver sur SigFox.
Je ne suis pas très bon programmeur alors j'ai fait comme toujours avec mes Arduinos, j'ai utilisé des bouts de code déjà faits.
Hors je ne sais pas trop comment formater mes données pour qu'elles correspondent à L'API openwindmap et surtout à mettre tout ça en lien.
Concernant les mesures, si jamais je pouvais "coller " aux données envoyées par un pioupiou V1 ce serait super (fréquence des mesures, calcul des valeurs min, moy et max).
Voilà je poste le code brut tel que je l'ai abandonné il y a 2 ans:// ------------------------------------------------------------------------- // This project sends Davis sensor windspeed and direction through Sigfox network // Start: 07.12.2017 // Author: Cédric CAMBON // With the original code from // Author: Antoine de Chassey // Code: https://github.com/AntoinedeChassey/MKRFOX1200_weather_station // and // cactus.io // http://cactus.io/hookups/weather/anemometer/davis/hookup-arduino-to-davis-anemometer //Hardware: Arduino MKRFox1200 + Davis anemometer // -------------------------------------------------------------------------- #include "SigFox.h" #include "ArduinoLowPower.h" #include "TimerOne.h" // Timer Interrupt set to 2 second for read sensors #include <math.h> // Connect Red Wire to ground // Connect Black wire to Digital input 2 with a 4k7 resistor pull up to 3,3V // Connect Yellow Wire to 3,3V // Connect Green Wire to Anbalog input 4 #define SpeedPin (2) // What digital pin we're connected to #define DirectionPin (A4) #define SLEEPTIME 10 * 60 * 1000 // Set the delay to 10 minutes (10 min x 60 seconds x 1000 milliseconds) #define UINT16_t_MAX 65536 #define INT16_t_MAX UINT16_t_MAX/2 int16_t VaneValue; // raw analog value from wind vane int16_t Direction; // translated 0 - 360 direction int16_t LastValue; volatile bool IsSampleRequired; // this is set true every 2.5s. Get wind speed volatile unsigned int TimerCount; // used to determine 2.5sec timer count volatile unsigned long Rotations; // cup rotation counter used in interrupt routine volatile unsigned long ContactBounceTime; // Timer to avoid contact bounce in interrupt routine int16_t Speed; // speed kilometers per hour typedef struct __attribute__ ((packed)) sigfox_message { int16_t moduleTemperature; int16_t WindSpeed; uint16_t WindDirection; uint8_t lastMessageStatus; } SigfoxMessage; // Stub for message which will be sent SigfoxMessage msg; void setup() { LastValue = 0; IsSampleRequired = false; TimerCount = 0; Rotations = 0; // Set Rotations to 0 ready for calculations pinMode(SpeedPin, INPUT); attachInterrupt(digitalPinToInterrupt(SpeedPin), isr_rotation, FALLING); // Setup the timer intterupt Timer1.initialize(500000); Timer1.attachInterrupt(isr_timer); if (!SigFox.begin()) { // Something is really wrong, try rebooting // Reboot is useful if we are powering the board using an unreliable power source // (eg. solar panels or other energy harvesting methods) reboot(); } // Send module to standby until we need to send a message SigFox.end(); } void loop() { float t = 0; getWindDirection(); // Only update the display if change greater than 5 degrees. if(abs(Direction - LastValue) > 5) { LastValue = Direction; } msg.WindDirection = Direction; if(IsSampleRequired) { // convert to km/h using the formula V=P(2.25 *1.609/T) // V = P *1.4481 Speed = Rotations * 1.4481; Rotations = 0; // Reset count for next sample IsSampleRequired = false; } msg.WindSpeed= Speed; // Start the module SigFox.begin(); // Wait at least 30ms after first configuration (100ms before) delay(100); // We can only read the module temperature before SigFox.end() t = SigFox.internalTemperature(); msg.moduleTemperature = convertoFloatToInt16(t, 60, -60); // Clears all pending interrupts SigFox.status(); delay(1); SigFox.beginPacket(); SigFox.write((uint8_t*)&msg, 12); msg.lastMessageStatus = SigFox.endPacket(); SigFox.end(); //Sleep for 10 minutes LowPower.sleep(SLEEPTIME); } void reboot() { NVIC_SystemReset(); while (1) ; } // isr routine fr timer interrupt void isr_timer() { TimerCount++; if(TimerCount == 5) { IsSampleRequired = true; TimerCount = 0; } } // This is the function that the interrupt calls to increment the rotation count void isr_rotation () { if ((millis() - ContactBounceTime) > 15 ) { // debounce the switch contact. Rotations++; ContactBounceTime = millis(); } } // Get Wind Direction void getWindDirection() { VaneValue = analogRead(DirectionPin); Direction = map(VaneValue, 0, 1023, 0, 360); if(Direction > 360) Direction = Direction - 360; if(Direction < 0) Direction = Direction + 360; } int16_t convertoFloatToInt16(float value, long max, long min) { float conversionFactor = (float) (INT16_t_MAX) / (float)(max - min); return (int16_t)(value * conversionFactor); }
Voilà. Je n'ai pas remis le nez dedans depuis 2 ans mais je m'y remets doucement. J'ai une version avec des timers mais pour optimiser la consommation j'ai préféré faire déjà faire une version de mesure continue pour regarder la conso et insérer plus tard des mises en veille...
Si jamais quelqu'un (Nicolas par exemple...) veut bien me renseigner, je suis pas sur d'avoir le courage de fouiller dans le code de la PiouPiou pour avoir ces infos.
A bientôt. -
@CAMBON
courage, il en faut, et tous les apports partagés sont bienvenus. on encourage ... -
Ah je me suis trompé, j'ai mis le mauvais Code avec le timer et trop tard pour faire un edit, voici le bon:
#include <math.h> #include "RunningAverage.h" // Connect Red Wire to ground // Connect Black wire to Digital input 2 // Connect Yellow Wire to 3,3V // Connect Green Wire to Anbalog input 4 #define SpeedPin (3) // What digital pin we're connected to #define DirectionPin (A4) #define Sample_qty 60 //Sample qty expected before sending message #define Sample_Time 10000 //Time for Windspeed measurement #define UINT16_t_MAX 65536 #define INT16_t_MAX UINT16_t_MAX/2 int16_t VaneValue; // raw analog value from wind vane int16_t Direction; // translated 0 - 360 direction int16_t LastValue; int16_t Sample_count; volatile unsigned long Rotations; // cup rotation counter used in interrupt routine volatile unsigned long ContactBounceTime; // Timer to avoid contact bounce in interrupt routine float Speed; // speed kilometers per hour typedef struct __attribute__ ((packed)) sigfox_message { int16_t WindSpeed; int16_t WindSpeedMax; int16_t WindSpeedMin; uint16_t WindDirection; uint8_t lastMessageStatus; } SigfoxMessage; // Stub for message which will be sent SigfoxMessage msg; RunningAverage Spedd_Av(Sample_qty); RunningAverage Direction_Av(Sample_qty); void setup() { Sample_count = 0; LastValue = 0; Spedd_Av.clear(); // explicitly start clean Direction_Av.clear(); pinMode(SpeedPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(SpeedPin), isr_rotation, FALLING); if (!SigFox.begin()) { // Something is really wrong, try rebooting // Reboot is useful if we are powering the board using an unreliable power source // (eg. solar panels or other energy harvesting methods) reboot(); } // Send module to standby until we need to send a message SigFox.end(); } void loop() { float t = 0; //??????????????????????????? for (int i=0; i <= Sample_qty; i++) { getSamples(); } msg.WindSpeed = convertoFloatToInt16(Spedd_Av.getAverage(), 60, -60);; // msg.WindDirection = Direction_Avn.getAverage(); // Start the module SigFox.begin(); // Wait at least 30ms after first configuration (100ms before) delay(100); // We can only read the module temperature before SigFox.end() t = SigFox.internalTemperature(); msg.moduleTemperature = convertoFloatToInt16(t, 60, -60); // Clears all pending interrupts SigFox.status(); delay(1); SigFox.beginPacket(); SigFox.write((uint8_t*)&msg, 12); msg.lastMessageStatus = SigFox.endPacket(); SigFox.end(); } void reboot() { NVIC_SystemReset(); while (1) ; } // This is the function that the interrupt calls to increment the rotation count void isr_rotation () { if ((millis() - ContactBounceTime) > 15 ) { // debounce the switch contact. Rotations++; ContactBounceTime = millis(); } } //Get Speed and direction values void getSamples () { //Get Wind Speed Rotations = 0; // Set Rotations to 0 ready for calculations interrupts(); // Enables interrupts delay (Sample_Time); // Wait n seconds to average noInterrupts(); // Disable interrupts Speed = (Rotations * 3.621015)/ Sample_Time; Speed_Av.addValue(Speed); //Add value to Speed array // Get Wind Direction VaneValue = analogRead(DirectionPin); Direction = map(VaneValue, 0, 1023, 0, 360); if(Direction > 360) Direction = Direction - 360; if(Direction < 0) Direction = Direction + 360; Direction_Av.addValue(Direction); //Add value to Direction array } int16_t convertoFloatToInt16(float value, long max, long min) { float conversionFactor = (float) (INT16_t_MAX) / (float)(max - min); return (int16_t)(value * conversionFactor); }
Je continue à travailler dessus.
-
Voici le code que tu peux utiliser.
Avec ça, je pourrai te connecter facilement à notre backend.// pour transmettre 2 périodes / message : // message de 8 bytes typedef struct __attribute__ ((packed)) sigfox_wind_message { int8_t speedMin[2]; int8_t speedAvg[2]; int8_t speedMax[2]; int8_t directionAvg[2]; } SigfoxWindMessage; // /!\ avec ce format, il faut transmettre // impérativement deux périodes de 5 minutes // xxx[0] -> de T-10 à T-5 minutes // xxx[1] -> de T-5 minutes à T // T étant l'heure de transmission
// alternativement, pour transmettre 1 période / message : // à la fréquence que vous voulez // (maximum toute les 10 minutes) // message de 4 bytes typedef struct __attribute__ ((packed)) sigfox_wind_message { int8_t speedMin; int8_t speedAvg; int8_t speedMax; int8_t directionAvg; } SigfoxWindMessage;
// pour l'encodage du vent sur 1 byte // (code original du Pioupiou) uint8_t encodeWindSpeed (float speedKmh) { uint8_t encodedSpeed; if (speedKmh < 10.) { // 0 to 9.75 kmh : 0.25 km/h resolution encodedSpeed = (uint8_t)(float)(speedKmh * 4. + 0.5); } else if (speedKmh < 80.) { // 10 to 79.5 kmh : 0.5 km/h resolution encodedSpeed = (uint8_t)(float)(speedKmh * 2. + 0.5) + 20; } else if (speedKmh < 120.) { // 80 to 119 kmh : 1 km/h resolution encodedSpeed = (uint8_t)(float)(speedKmh + 0.5) + 100; } else if (speedKmh < 190.) { // 120 to 188 kmh : 2 km/h resolution encodedSpeed = (uint8_t)(float)(speedKmh / 2. + 0.5) + 160; } else { // 190 or + : out of range encodedSpeed = 0xFF; } return encodedSpeed; }
// pour l'encodage de la direction sur 1 byte uint8_t encodeWindDirection (float direction) { // radians direction = direction / M_PI * 180.; // radians to degrees if (direction < 0.) direction += 360.; // -180-180 to 0-360+ // encode with 2° precision // add 0.5 for rounding when converting from (float) to (int) return (uint8_t)(float)(direction / 2. + 0.5); }
-
Merci Nicolas. Je vais tester ça.
-
Pour ensuite connecter l'appareil au réseau OpenWindMap, faîtes une demande ici :
https://forum.openwindmap.org/topic/221/connecter-un-arduino-mkr-fox-à-openwindmap/1 -
@nicolas j'ai réalisé il y a 2ans
Une station météo connecté
Avec un esp8266
Qui fonctionne aussi en 3.3v mais je l'alimente avec un ancien chargeur de portable micro usb
Il se connect au wifi tout seul et transmet les données sur thing view
Et j'ai connecté dessus 2 sonde température humidité une intérieur une extérieur et un anémomètre la crosse tx21 avec 4 connection par fil cuivreEt ça fonctionne plutôt bien
Est ce le même principe mais avec une puce sigfox au lieu d'une wifi sur votre projet? -
Bonjour,
J'essaye de comprendre les données.
Sigfox envoi toutes les 10 min, je vois (si je comprend bien) que dans chaque message il y 2 série de données:Ici c'est un peu plus clair :
J'aimerai avoir des infos sur l'enregistrement des données.
Dans l'exemple à 19h18 j'ai 26.5 km/h cette valeur est une moyenne entre 19h13 et 19h18? La valeur la plus haute entre 19h13 et 19h18? La valeur a 19h18?
Je pense qu'il faudrait qq explications.
Merci -
@toby said in Format messages Sigfox de Arduino vers OpenWindMap:
Bonjour,
J'essaye de comprendre les données.
Sigfox envoi toutes les 10 min, je vois (si je comprend bien) que dans chaque message il y 2 série de données:Ici c'est un peu plus clair :
J'aimerai avoir des infos sur l'enregistrement des données.
Dans l'exemple à 19h18 j'ai 26.5 km/h cette valeur est une moyenne entre 19h13 et 19h18? La valeur la plus haute entre 19h13 et 19h18? La valeur a 19h18?
Je pense qu'il faudrait qq explications.
MerciPuis-je obtenir une réponse? Merci.
-
Donc, sur la période qui va de 19h13 à 19h18 (UTC) on a mesuré :
au minimum : 0 km/h
au maximum : 26.5 km/h
en moyenne : 3km/h
(échantillonnage WMO de 3 secondes sur ce modèle de balise arduino) -
@nicolas said in Format messages Sigfox de Arduino vers OpenWindMap:
Donc, sur la période qui va de 19h13 à 19h18 (UTC) on a mesuré :
au minimum : 0 km/h
au maximum : 26.5 km/h
en moyenne : 3km/h
(échantillonnage WMO de 3 secondes sur ce modèle de balise arduino)Bonjour,
Merci, c'est plus clair. J'ai de quoi argumenter le montage d'un des deux entre Sintra et Cascais, couloir très venteux que peu de personnes connaissent! Mais pas évident à convaincre.
PS: le 2ème je n'ai pas encore décider où le mettre. (Nazaré?)
Bon we