Aller au contenu

Driver ASCOM avec arduino nouvelle version!!


astrolivier

Messages recommandés

Bonjour à tous,

 

voilà plusieurs années que je m'amuse avec des arduino et l'impression 3D.

J'ai par le passé fait beaucoup de projet dont un ici sur un FlipFlat pas cher.

La seule chose que je n'ai pas faite est un driver ASCOM car celui ci existait déjà et seule la partie arduino était à faire.

J'ai, il y a quelques années, réalisé un petit driver isafetymonitor ASCOM en VB. Pour cela j'avais conçu une petite station météo constituée d'un capteur BME280, d'un MLX90614 et un TSL2591.

J'ai dans l'idée aujourd'hui de me faire un petit driver ASCOM ObservingConditions dans le but de l'utiliser avec NINA. J'aimerai par ailleurs que ce driver ASCOM permette aussi d'étre utilisé en simultané en tant que driver safetymonitor (pas encore implanté dans mon code arduino). J'ai lu que c'était possible.

Et c'est là que les problèmes commencent!!

J'ai installé VS2022 et installé les templates ASCOM qui sont au nombre de 3.

Bon, déjà ici tout est bien différent de l'époque en VB où j'avais pu suivre le tuto de la roue à filtre de Tom Haw sur Youtube.

La maintenant il faut créer un code en C#. Bon allez, on reprends les bases mais ca va le faire.

Nouvelle complexité: On parle maintenant d'un driver en mode LocalServer.... ok.... bon je lis toute la documentation en anglais mais je pige pas tout.

 

Bref, je commence à regarder dans VS2022.

J'ouvre le premier template et dans l'arboresence je me retoruve avec plein de nouveaux fichiers dont:

-observingconditions.cs et observingconditionhardware.cs

 

Je me suis arrêter ici car forcément je ne vois pas du tout par où aller, ni commencer.

 

Je vous joins ci après mon firmware arduino avec son protocole série.

Je vous joins également les éléments sous forme de fichier C# que je pense devoir integrer dans le driver ASCOM.

 

Pourriez vous m'aider sur la conception de ce driver ASCOM?

je sais qu'il existe des projets un peu identique mais j'aimerai réellement le faire de 1 à Z ce projet! cela me rendrait fier et j'ai d'autres idées en tête.

Donc plutôt que de copier, si je peux comprendre comment tout cela marche et s'implémente alors ce serait génial.

 

Code arduino:

// librairies de base
#include <Wire.h>
#include <Adafruit_Sensor.h>
//#include <math.h>

#define delais 1000 //temps entre deux maj des valeurs en ms
#define SerialSpeed 9600 // vitesse de communication sur le port série

// utilisation d'un BME280 Velleman WPSE335
#include <BME280I2C.h>
BME280I2C bme;
float temperature_ambiante_BME;
float pression_locale;
float correction_altitude_pression = 0.00; //facteur de correction lié à l'altitude locale
float humidite;
float dewpoint;

// utilisation d'un MLX90614
#include <Adafruit_MLX90614.h>
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
float temperature_ambiante_MLX;
float temperature_ciel;
float correction_temperature;
float temperature_ciel_corrigee;
#define  K1 33.
#define  K2 0.
#define  K3 4.
#define  K4 100.
#define  K5 100.
#define  K6 0.
#define  K7 0.
float CWT; //CWT = Cold Weather correction en cas de basse temperature (<1°C)
// température ciel completement clair
#define temperature_ciel_clair  -8
// température ciel completement couvert
#define temperature_ciel_couvert  0
//Activation treshold for cloudFlag (%)


// utilisation d'un TSL2591
#include <Adafruit_TSL2591.h>
Adafruit_TSL2591 tsl = Adafruit_TSL2591();
struct {
  bool status;
  uint32_t full;
  uint16_t ir;
  uint16_t visible;
  int      gain;
  int      timing;
  float    lux;
} tsl2591Data {false, 0, 0, 0, 0, 0, 0.0};

/**
   tsl.begin() always returns true, hence we need to check the I2C adress
*/
bool isTSL2591Present() {
  Wire.beginTransmission(TSL2591_ADDR);
  byte error = Wire.endTransmission();

  return (error == 0);
}

void configureSensorTSL2591(tsl2591Gain_t gainSetting, tsl2591IntegrationTime_t timeSetting)
{
  // You can change the gain on the fly, to adapt to brighter/dimmer light situations
  tsl.setGain(gainSetting);

  // Changing the integration time gives you a longer time over which to sense light
  // longer timelines are slower, but are good in very low light situtations!
  tsl.setTiming(timeSetting);
}

// calibrate TSL2591 gain and integration time
bool calibrateTSL2591() {
  if (tsl2591Data.visible < 100) { //Increase GAIN (and INTEGRATIONTIME) if light level too low
    switch (tsl2591Data.gain)
    {
      case TSL2591_GAIN_LOW :
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_MED :
        configureSensorTSL2591(TSL2591_GAIN_HIGH, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_HIGH :
        configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_MAX :
        switch (tsl2591Data.timing)
        {
          case TSL2591_INTEGRATIONTIME_200MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_300MS);
            break;
          case TSL2591_INTEGRATIONTIME_300MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_400MS);
            break;
          case TSL2591_INTEGRATIONTIME_400MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_500MS);
            break;
          case TSL2591_INTEGRATIONTIME_500MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_600MS);
            break;
          case TSL2591_INTEGRATIONTIME_600MS :
            // no higher sensitivity level available
            return false;
            break;
          default:
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_600MS);
            break;
        }
        break;
      default:
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
    }

    // calibration changed
    return true;
  }

  if (tsl2591Data.visible > 30000) { //Decrease GAIN (and INTEGRATIONTIME) if light level too high
    switch (tsl2591Data.gain)
    {
      case TSL2591_GAIN_LOW :
        switch (tsl2591Data.timing)
        {
          case TSL2591_INTEGRATIONTIME_500MS :
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_400MS);
            break;
          case TSL2591_INTEGRATIONTIME_400MS :
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_300MS);
            break;
          case TSL2591_INTEGRATIONTIME_300MS :
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_200MS);
            break;
          case TSL2591_INTEGRATIONTIME_200MS :
            // no higher sensitivity level available
            return false;
            break;

          default:
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_200MS);
            break;
        }
        break;
      case TSL2591_GAIN_MED :
        configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_HIGH :
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_MAX :
        configureSensorTSL2591(TSL2591_GAIN_HIGH, TSL2591_INTEGRATIONTIME_200MS);
        break;
      default:
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
    }
    // calibraton changed
    return true;
  }

  // no calibration change necessary
  return false;
}

void setup() {
  Serial.begin(SerialSpeed);
  Wire.begin();
  bme.begin();
  mlx.begin();
 }

void updateBME() {
  float temp(NAN), hum(NAN), pres(NAN);
  BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
  BME280::PresUnit presUnit(BME280::PresUnit_hPa);
  bme.read(pres, temp, hum, tempUnit, presUnit);
  temperature_ambiante_BME = temp;
  pression_locale          = pres+correction_altitude_pression;
  humidite                 = hum;
}

void updateMLX() {

    temperature_ambiante_MLX = mlx.readAmbientTempC();
    temperature_ciel         = mlx.readObjectTempC();
}

void updateTSL2591() {
    tsl.begin();
    // Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum
    tsl2591Data.full    = tsl.getFullLuminosity();
    tsl2591Data.ir      = tsl2591Data.full >> 16;
    tsl2591Data.visible = tsl2591Data.full & 0xFFFF;
    tsl2591Data.lux     = tsl.calculateLux(tsl2591Data.visible, tsl2591Data.ir);
    tsl2591Data.gain    = tsl.getGain();
    tsl2591Data.timing  = tsl.getTiming();

    bool changed = calibrateTSL2591();
    if (changed) updateTSL2591();
}

void loop() {
 String cmd;
 if (Serial.available() > 0) 
  {
  updateBME();
  updateMLX();
  correction_temperature = (K1 / 100) * (temperature_ambiante_MLX - K2 / 10) + (K3 / 100) * pow((exp (K4 / 1000* temperature_ambiante_MLX)) , (K5 / 100))+CWT;
  temperature_ciel_corrigee = temperature_ciel - correction_temperature;
  dewpoint = ((sqrt(sqrt(sqrt(humidite/100))))*(110+temperature_ambiante_BME))-110;
  updateTSL2591();
  
  cmd = Serial.readStringUntil('\n');

  if(cmd =="GETDATA") 
   {
    Serial.print("T:");
    Serial.print(temperature_ambiante_BME,1);
    Serial.print(",C:");
    Serial.print(temperature_ciel_corrigee,1);   
    Serial.print(",P:");
    Serial.print(pression_locale,1);
    Serial.print(",H:");
    Serial.print(humidite,1);
    Serial.print(",D:");
    Serial.print(dewpoint,1);
    Serial.print(",L:");
    Serial.println(tsl2591Data.lux,1);        
   } 
 }
 delay(delais);
}

 

Code a integrer je sais pas ou dans driver ASCOM ObservingConditions:

using ASCOM;
using System.IO.Ports;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Threading;
using ASCOM.Astrometry.AstroUtils;
using ASCOM.DeviceInterface;
using ASCOM.Utilities;

namespace ASCOM.MyObservingConditions
{
    public class ObservingConditions : IObservingConditions
    {
        private double temperature;
        private double skytemperature;
        private double pression;
        private double humidity;
        private double dewpoint;
        private double skyluminosite;
        private SerialPort arduinoPort;

        public ObservingConditions(string comPort)
        {
            arduinoPort = new SerialPort(comPort, 9600);
            arduinoPort.Open();
        }

        public double AveragePeriod { get; set; }

        public void Refresh()
        {
            arduinoPort.Write("GETDATA");

            string response = arduinoPort.ReadLine();
            string[] values = response.Split(',');

            if (values.Length == 6 && double.TryParse(values[0].Substring(2), out double temp) && double.TryParse(values[1].Substring(2), out double skyT)&& double.TryParse(values[2].Substring(2), out double pres)&& double.TryParse(values[3].Substring(2), out double hum)&& double.TryParse(values[4].Substring(2), out double dew)&& double.TryParse(values[5].Substring(2), out double skyL))
            {
                temperature = temp;
                skystemperature = skyT;
                pression = pres;
                humidity = hum;
                dewpoint = dew;
                skyluminosite = skyL;
            }
            else
            {
                temperature = 0;
                skystemperature = 0;
                pression = 0;
                humidity = 0;
                dewpoint = 0;
                skyluminosite = 0;
            }
        }

        public double Temperature
        {
            get { return temperature; }
            private set { temperature = value; }
        }

         public double SkyTemperature
        {
            get { return skytemperature; }
            private set { skytemperature = value; }
        }

          public double Pressure
        {
            get { return pression; }
            private set { pression = value; }
        }              

        public double Humidity
        {
            get { return humidity; }
            private set { humidity = value; }
        }

         public double DewPoint
        {
            get { return dewpoint; }
            private set { dewpoint = value; }
        }       

         public double SkyBrightness
        {
            get { return skyluminosite; }
            private set { skyluminosite = value; }
        }

        ~ObservingConditions()
        {
            arduinoPort.Close();
        }
    }
}

 

Merci pour votre aide. :)

 

Olivier

  • J'aime 1
Lien vers le commentaire
Partager sur d’autres sites

Je souhaite apporter quelques informations:

Voici ma démarche pour créer le driver ASCOM:

Dans VS 2022 en mode administrateur:

image.png.9874d15a71d0ab5658aa43b9648eb609.png

 

Je choisi le 1er: ASCOM Driver Template et je clique sur suivant.

Puis,

image.png.087e752757a16850659621fc5d22e791.png

 

et je clique sur créer, ce qui ouvre cette boite de dialogue et que je rempli ainsi:

image.png.e5dddcb2045e215fae998294b55839eb.png

 

Enfin je clique sur créer:

Voilà l'arborescence des fichiers:

image.png.37659f20d4aa57f635890129c208c825.png

 

Voilà, c'est ici que j'ai besoin de vous :)

 

Par où commencer, où implanter mes différentes fonctions etc... autant de questions que j'ai envie de poser!!!

 

Merci

Lien vers le commentaire
Partager sur d’autres sites

Posté (modifié)

J'ai créé une discussion dans le forum coté "logiciel" car ici c'est censé être purement arduino.

Je limite donc le nombre de vue au 63 personnes du club.

En  faisant cette passerelle j'espère pouvoir attirer plus de personne et ainsi pouvoir évoluer dans ma compréhension de cette nouvelle façon de créer un driver ASCOM.

 

Modifié par astrolivier
Lien vers le commentaire
Partager sur d’autres sites

Salut, je bosse mes drivers en Vb.net plus rapide et même résultat. 

Les fonctions sont claires as tu regardé les nombreuses docs des librairies dont celle concernée ObservingConditions ? 

Le fichier des fonctions est ObservingConditionsDriver.cs je suppose...je vais en editer un en C pour regarder 

 

A suivre ...

Modifié par Raphael_OD
  • J'aime 1
Lien vers le commentaire
Partager sur d’autres sites

Merci de s’y interesser.

alors a l’epoque il n’y avait que le fichier driver.vb qu’il fallait editer.

la a priori il y a 2 fichier en .cs a renseigner (avec a priori un peu la meme architecture).

Et je ne parle meme pas d’alpaga!!

en soit les arguments semblent facilent a comprendre.

moi c’est plus ou renseigner tout cela!!

toute aide sera vraiment bienvenue :)

et les codes que j’ai mis sont complètement ouverts et libres, s’il faut (et c’est meme sur) les modifier ^^

Lien vers le commentaire
Partager sur d’autres sites

Concernant VS2022, si tu n'as pas envie de faire un driver en mode "local server" comme ASCOM veut nous forcer à faire maintenant (😒 )... tu peux toujours installer VS2019 et là tu pourras faire une driver classique.  C'est à toit de voir ce dont tu as besoin. Si tu as besoin du serveur local, je pourrai pas aider là là dessus. J'ai jamais eu à implémenter cela dans mes drivers ASCOM. Si je dois faire un petit driver, je le crée sur VS2019 et après j'en fais ce que je veux.

Néanmoins, si je créée rapidement un driver Observing conditions sur VS2022, je vois dans l'explorer un dossier "ObservingConditionsDriver" avec deux fichiers .CS dedans. En regardant les commentaires dans le code, ils disent clairement qu'il veut mieux ne pas toucher à  "ObservingConditionsDriver.cs" et que tu dois juste implémenter tes fonctions principales dans "ObservingConditionsHardware.cs".

 

Donc si on ouvre ce dernier, tu peux déployer les sections pour avoir accès à ce que tu as besoin avec tous les fonctions typiques qu'on retrouverait dans un driver ASCOM à l'ancienne. Entre autres, la région "IObservingConditions Implementation" expose toutes les grandeurs que tu veux utiliser ( des choses comme la température, la pression, l'humidité etc, à toi de voir)  et c'est ça que le client appellera pour récupérer ses données ou en envoyer à l'appareil.  Donc ce fichier se code comme un driver ascom normal à priori. Voilà :)

 

 

Lien vers le commentaire
Partager sur d’autres sites

Et concernant la gestion du port Série, il te faudra probablement un EventHandler ( je sais pas si ça existe en VB) qui permettra d'appeler une fonction  dès que de nouvelles données sont reçues sur le port Série.

 

Perso j'instancie le port Série dans la méthode Connected ( la partie set pour être précis), plutôt dans le constructeur de la classe comme toi.

Et juste après ça, tu va utiliser l'EventHandler  du port "DataReceived" et le faire pointer vers une fonction à toi ( chez moi je la nomme port_DataReceived).

 

public bool Connected
        {
            get
            {
                LogMessage("Connected", "Get {0}", IsConnected);
                return IsConnected;
            }
            set
            {
                tl.LogMessage("Connected", "Set {0}", value);
                if (value == IsConnected)
                    return;

                if (value)
                {
                    connectedState = true;
                    LogMessage("Connected Set", "Connecting to port {0}", comPort);


                    port = new SerialPort(comPort, 9600);//Set your board COM
                    port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
                    port.Open();

                }
                else
                {
                    connectedState = false;
                    LogMessage("Connected Set", "Disconnecting from port {0}", comPort);

                    port.Close();
                }
            }
        }

 

Et ensuite la fonction callback "port_DataReceived", elle sera comme cela par exemple

 

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            string a = port.ReadLine();
         
            //Et là à toi de voir comment manipuler le string pour en sortir tes données, c'est toi qui décide comment c'est mis en forme dans l'arduino.
        }

 

 

  • J'aime 1
Lien vers le commentaire
Partager sur d’autres sites

Bonjour @Antiath,

Merci pour ton retour que je lis avec beaucoup d'attention.

Je me suis résoud à utiliser la verison 2022 car il disent qu'un jour les drivers ascom classiques pourraient un jour ne plus fonctionner.

J'avoue que je m'étais dis que je repasserais bien à la version 2019 ^^

D'autant que la vidéo de Tom Haw m'avait permis à l'époque de facilement réaliser un petit driver Isafety :)

 

Un grand merci pour le code.

Il faut que je relise bien tout cela car même si j'utilise les arduino depuis quelques années c'est la seule chose que "je sais coder".

Donc que ce soit en C ou en VB pour moi créer un driver ascom n'est pas simple.

Mais je suis quelqu'un de perseverant et j'aimerai reellement comprendre le fonctionnement, car une fois ce petit driver fonctionnel il sera juste à adapter pour mes prochaines réalisations :)

 

Lien vers le commentaire
Partager sur d’autres sites

Posté (modifié)

Messieurs,

 

suite à vos commentaires, voici un premier jet du code où je ne laisse apparaitre que ce que j'ai ajouté et / ou modifié.

Comme souligné je n'ai ajouté ce code que dans le fichier observingconditionhardware.cs

Je vous joins le code complet en PJ

 

N'étant pas sur de savoir où implémentais la requête vers l'arduino (le fameux arduinoport.Write("GETDATA") pouvais vous le relire voir essayer?

 

// TODO fill in this information for your driver, then remove this line!
//
// ASCOM ObservingConditions hardware class for MeteoAstrolivier76
//
// Description:     <To be completed by driver developer>
//
// Implements:    ASCOM ObservingConditions interface version: <To be completed by driver developer>
// Author:        (XXX) Your N. Here <your@email.here>
//

using ASCOM;
using ASCOM.Astrometry;
using ASCOM.Astrometry.AstroUtils;
using ASCOM.Astrometry.NOVAS;
using ASCOM.DeviceInterface;
using ASCOM.LocalServer;
using ASCOM.Utilities;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO.Ports;
using System.Linq.Expressions;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;

namespace ASCOM.MeteoAstrolivier76.ObservingConditions
{
    //
    // TODO Replace the not implemented exceptions with code to implement the function or throw the appropriate ASCOM exception.
    //

    /// <summary>
    /// ASCOM ObservingConditions hardware class for MeteoAstrolivier76.
    /// </summary>
    [HardwareClass()] // Class attribute flag this as a device hardware class that needs to be disposed by the local server when it exits.
    internal static class ObservingConditionsHardware
    {
        // Constants used for Profile persistence
        internal const string comPortProfileName = "COM Port";
        internal const string comPortDefault = "COM10";
        internal const string traceStateProfileName = "Trace Level";
        internal const string traceStateDefault = "true";

        private static string DriverProgId = ""; // ASCOM DeviceID (COM ProgID) for this driver, the value is set by the driver's class initialiser.
        private static string DriverDescription = ""; // The value is set by the driver's class initialiser.
        internal static string comPort; // COM port name (if required)
        private static bool connectedState; // Local server's connected state
        private static bool runOnce = false; // Flag to enable "one-off" activities only to run once.
        internal static Util utilities; // ASCOM Utilities object for use as required
        internal static AstroUtils astroUtilities; // ASCOM AstroUtilities object for use as required
        internal static TraceLogger tl; // Local server's trace logger object for diagnostic log with information that you specify

        private static SerialPort arduinoport;

        private static double temperature;
        private static double skytemperature;
        private static double pression;
        private static double humidity;
        private static double dewpoint;
        private static double skyluminosite;

        public static void ChooseCOMPort()
 {
     using (var portChooser = new ASCOM.Utilities.Chooser())
     {
         portChooser.DeviceType = "ObservingConditions";

         string selectedPort = portChooser.Choose();

         if (selectedPort == null)
         {
             // L'utilisateur a annulé la sélection du port COM.
             return;
         }

         // Mettez à jour la variable de port COM avec la sélection de l'utilisateur.
         comPort = selectedPort;
     }
 }

        /// <summary>
        /// Set True to connect to the device hardware. Set False to disconnect from the device hardware.
        /// You can also read the property to check whether it is connected. This reports the current hardware state.
        /// </summary>
        /// <value><c>true</c> if connected to the hardware; otherwise, <c>false</c>.</value>
        public static bool Connected
        {
            get
            {
                LogMessage("Connected", $"Get {IsConnected}");
                return IsConnected;
            }
            set
            {
                LogMessage("Connected", $"Set {value}");
                if (value == IsConnected)
                    return;

                if (value)
                {
                    LogMessage("Connected Set", $"Connecting to port {comPort}");

                    // TODO insert connect to the device code here
                    arduinoport = new SerialPort(comPort, 9600);//Set your board COM
                    arduinoport.DataReceived += new SerialDataReceivedEventHandler(arduinoport_DataReceived);
                    arduinoport.Open();
                    connectedState = true;
                }
                else
                {
                    LogMessage("Connected Set", $"Disconnecting from port {comPort}");

                    // TODO insert disconnect from the device code here

                    connectedState = false;
                    arduinoport.Close();
                }
            }
        }
        private static void arduinoport_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

            //Et là à toi de voir comment manipuler le string pour en sortir tes données, c'est toi qui décide comment c'est mis en forme dans l'arduino.
            arduinoport.Write("GETDATA");
            string responsearduino = arduinoport.ReadLine();
            string[] values = responsearduino.Split(',');
            if (values.Length == 6 && double.TryParse(values[0].Substring(2), out double temp) && double.TryParse(values[1].Substring(2), out double skyT) && double.TryParse(values[2].Substring(2), out double pres) && double.TryParse(values[3].Substring(2), out double hum) && double.TryParse(values[4].Substring(2), out double dew) && double.TryParse(values[5].Substring(2), out double skyL))
            {
                temperature = temp;
                skytemperature = skyT;
                pression = pres;
                humidity = hum;
                dewpoint = dew;
                skyluminosite = skyL;
            }
            else
            {
                temperature = 0;
                skytemperature = 0;
                pression = 0;
                humidity = 0;
                dewpoint = 0;
                skyluminosite = 0;
            }
        }
        
}

 

L'IDE m'indique qu'acune erreur n'a été trouvée.

Pour le moment je n'ai pas edité les différentes variables. J'aimerai déjà voir ce que vous en pensais?

C'est un petit pas pour l'homme mais un grand pas pour moi ^^

 

PS: on ne plus masqué le texte? cela éviterai d'avoir des pages énormes!! avant il y avait un oeil pour faire cela mais je ne le vois plus.

 

ObservingConditionsHardware.cs

Modifié par astrolivier
Lien vers le commentaire
Partager sur d’autres sites

Si tu mets  arduinoport.Write("GETDATA")  dans la fonction arduinoport_DataReceived,

à chaque fois que tu vas recevoir des données , il va renvoyer " GETDATA" à l'arduino. Je crois pas que ce soit le comportement que tu souhaites. Ca va saturer sur le port série.

 

Je vois dans ton firmware arduino que tu attends cette requête "GETDATA" pour répondre, donc effectivement de cette manière là, il faut que cette requête soit envoyée régulièrement par le driver. Il faut savoir à quel  endroit l'exécuter. Cela doit être fait à intervalle régulier...

- faut-il mettre en place un timer alors qui enverra la requête tous les x milisecondes ? Comment on fait ça en c# ?( jamais fait ça donc j'ai pas la réponse mais ça doit être possible)

- ou est-ce qu'on peut profiter du fait que le client va interroger le driver de façon régulière pour  envoyer GETDATA à chaque fois ?  Par exemple, le client va appeler régulièrement la fonction Temperature pour avoir la dernière valeur. Est-ce qu'on peut pas mettre la un arduinoport.Write("GETTEMPERATURE") ? Et si on fait ça est-ce qu'on bloque le driver tant que la réponse est pas arrivée ? Si oui comment ? Si non, que faire à la place ?

 Faut répondre à tout ça pour savoir quoi faire... Perso je trouve ça trop compliqué pour pas grand chose ...

 

Une autre stratégie c'est de simplement dire à l'arduino d'envoyer ses données tous les x secondes ( tu remarqueras que ASCOM prévoit une grandeur nommée AveragePeriod...peut etre on peut se servir de ça pour déterminer la fréquence à laquelle envoyer les données ?) . Côté driver, on se contente de récupérer ça dans arduinoport_DataReceived, de stocker les valeurs dans des variables non statiques  et de dire au driver de retourner ces variables  quand le client l’interroge.  On a plus à se demander comme ça comment gérer les timing depuis le driver, quelle fonction est bloquante ou non, c'est l'arduino qui mène la dance. Bien plus facile.

 

Par exemple

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            string a = port.ReadLine(); //Supposons que le string soit juste constitué de la température, rien que le nombre, aucun autre charactère. Pour simplifier
  			_temperature= double.Parse(a);
           
        }

private double _temperature =0; 
//j'initialise à 0. Cette variable me sert à sotcker la dernière valeur de température. port_DataReceived la met à jour à chaque fois que l'arduino lui envoie une valeur.

        /// <summary>
        /// Temperature at the observatory in deg C
        /// </summary>

//Cette fonction est déjà incluse dans le template, il suffit d'enlever les lignes qui disent que c'est pas implémenté et mettre ton code à la place
//C'est elle qui est appelée par le client quand il veut savoir la température.
internal static double Temperature
        {
            get
            {
                return _temperature;
            }
        }

 

Modifié par Antiath
Lien vers le commentaire
Partager sur d’autres sites

merci pour l’explication.

en effet je ne souhaite pas faire une requête a chaque réception de données.

je vois comment procéder pour la réception.

en revanche je ne vois pas a quel endroit alors il faut faire l’envoi de la commande Write(« GETDATA ») dans le driver.

Comme je le mentionnais le driver est encore incomplet cote valeurs.

Concernant les délais en faite je comptais en effet un délais dans la demande.

peut être avec la fonction Average.

je n’ai pas encore regardé cet aspect.

Et il y a déjà un délai dans le code arduino.

peut être mettre la même valeur.

 

disons qu’avant d’aller plus loin je souhaite déjà que ce code sans forcement avoir les valeurs de l’arduino fonctionne.

 

comment procéder pour l’essayer en l’etat ?

comment procedez vous?

Lien vers le commentaire
Partager sur d’autres sites

Ou alors on ne fait jamais de requêtes et on laisse a l’arduino le soin d’envoyer toutes les x secondes les valeurs sur le port serie.

dans ce cas le driver n’a plus qu’a lire les donnes et les afficher non?

Lien vers le commentaire
Partager sur d’autres sites

Si tu penses pouvoir tester le driver, et bien le plus simple c'est de le compiler. Dans VS, cliques sur Générer puis Nettoyer la solution, puis une fois fini,  Générer la solution. S'il n'y a aucun problème de compilation, alors le driver est automatiquement créé et enregistré par ASCOM sur ce pc. Il te suffit d'ouvrir ton client favori, genre NINA par ex et d'aller le trouver et te connecter.

C'est le plus simple mais comme ça, ça t'aidera pas si il y a un bug ( et il y en aura avec ce que tu as actuellement écrit).

Pour mieux débugger, le mieux c'est de faire un client toi même dans la même solution que le driver et demander à VS d'éxécuter la solution en pointant ce client.  Tu va dans l'explorateur de la solution, cliques droit sur la solution, Ajouter, Ajouter un projet, choisir un template ASCOM Windows form et là tu devras te débrouiller pour faire l'interface graphique, mettre des boutons, des zones de textes et du code qui appèlera le driver et affichera tes données. C'est trop long pour tout expliquer ici, il y a pléthores de tutoriels pour apprendre à faire ça sur VS, et probablement même des tuto spécialisé pour ASCOM qui expliquent exactement ça.

 

 

il y a 1 minute, astrolivier a dit :

Ou alors on ne fait jamais de requêtes et on laisse a l’arduino le soin d’envoyer toutes les x secondes les valeurs sur le port serie.

dans ce cas le driver n’a plus qu’a lire les donnes et les afficher non?

C'est exactement ce que j'expliquais plus haut. Comme ça, plus besoin d'envoyer GETDATA.

Lien vers le commentaire
Partager sur d’autres sites

Oh et une chose à faire une seule fois avant de tester le driver et de le compiler. Dans l'explorateur, cliques droit sur le projet ( jusque en dessous de la solution..désolé le vocabulaire de VS est particulier ...) , puis propriétés. Sur l'onglet Générer ( Buil en anglais chez moi), tu pourras lui préciser quelle plateforme viser. Par défaut ce sera probablement x86. Il vaut mieux mettre en x64 si ta machine a un processeur x64. Nina sera pas content sinon et je pense que les autres clients non plus.

 

image.thumb.png.96b656833088c8c3b813aabd457f01aa.png

Modifié par Antiath
Lien vers le commentaire
Partager sur d’autres sites

Merci beaucoup pour toutes ces informations.

je partagerai sans pb les codes finaux mais comme tu le dis il y a du boulot. Et pour être honnête ce n’est pas ma priorité.

Le code arduino ni le driver ne sont terminés, j’en suis bien conscient!

ce qui m’énerve le plus c’est que j’ai les idées mais je suis bloqué par cette programmation. Ça a l’air a la fois très simple et en même temps très dur!

 Rien que pour générer une solution et la debuger, il va me falloir relire les messages ^^

Je vais relire et continuer.

mais si on pouvait simplement tester (un peu a la serial dans l’ide arduino ce serait trop top ^^)

Lien vers le commentaire
Partager sur d’autres sites

L'avantage si tu fais le client toi même et que tu éxecutes tout au sein même de VS en cliquant sur le triangle vert, si il y a un bug, VS va s'arrêter sur la partie problématique, pointer la ligne de code et afficher la sortie du debugger.. Tu peux même utiliser des breakpoint ( en cliquant sur le côté d'une ligne de code pour faire apparaitre un cercle rouge)  où le code pausera et tu pourras examiner le contenu des variables. C'est magique.

Lien vers le commentaire
Partager sur d’autres sites

il y a une heure, Antiath a dit :

L'avantage si tu fais le client toi même et que tu éxecutes tout au sein même de VS en cliquant sur le triangle vert, si il y a un bug, VS va s'arrêter sur la partie problématique, pointer la ligne de code et afficher la sortie du debugger.. Tu peux même utiliser des breakpoint ( en cliquant sur le côté d'une ligne de code pour faire apparaitre un cercle rouge)  où le code pausera et tu pourras examiner le contenu des variables. C'est magique.

J'en suis bien conscient! mais cela va rajouter de la complexité et de la compréhension de ma part!! Disons que déjà repasser en C# ce n'est pas simple alors de là à créer une boite de dialogue!! c'est pas pour demain le driver ^^

Mais comme je disais je suis plutôt déterminé donc je vais essayer.

Je vais essayer de regarder des tutos histoire d'essayer.

Je viens de reprendre un peu mon code arduino et rajouter les fonctions au code ascom.

J'ai regardé pour la partie Average mais il ne semble pas que ce soit utile pour mon driver. Cela sert à faire une moyenne sur un intervalle de temps.

En revanche il y a la fonction timelastupdate et là ça semble plus utile. Il suffit de lancer un chrono et une fois le delai dépasser il peut lire le port serie. Un truc du genre:

 

Code arduino:

// librairies de base
#include <Wire.h>
#include <Adafruit_Sensor.h>
//#include <math.h>

#define delais 5000 //temps entre deux maj des valeurs en ms
#define SerialSpeed 9600 // vitesse de communication sur le port série

// utilisation d'un BME280 Velleman WPSE335
#include <BME280I2C.h>
BME280I2C bme;
float temperature_ambiante_BME;
float pression_locale;
float correction_altitude_pression = 0.00; //facteur de correction lié à l'altitude locale
float humidite;
float dewpoint;
float nuages;

// utilisation d'un MLX90614
#include <Adafruit_MLX90614.h>
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
float temperature_ambiante_MLX;
float temperature_ciel;
float correction_temperature;
float temperature_ciel_corrigee;
#define  K1 33.
#define  K2 0.
#define  K3 4.
#define  K4 100.
#define  K5 100.
#define  K6 0.
#define  K7 0.
float CWT; //CWT = Cold Weather correction en cas de basse temperature (<1°C)
// température ciel completement clair
#define temperature_ciel_clair  -8
// température ciel completement couvert
#define temperature_ciel_couvert  0
//Activation treshold for cloudFlag (%)


// utilisation d'un TSL2591
#include <Adafruit_TSL2591.h>
Adafruit_TSL2591 tsl = Adafruit_TSL2591();
struct {
  bool status;
  uint32_t full;
  uint16_t ir;
  uint16_t visible;
  int      gain;
  int      timing;
  float    lux;
} tsl2591Data {false, 0, 0, 0, 0, 0, 0.0};

/**
   tsl.begin() always returns true, hence we need to check the I2C adress
*/
bool isTSL2591Present() {
  Wire.beginTransmission(TSL2591_ADDR);
  byte error = Wire.endTransmission();

  return (error == 0);
}

void configureSensorTSL2591(tsl2591Gain_t gainSetting, tsl2591IntegrationTime_t timeSetting)
{
  // You can change the gain on the fly, to adapt to brighter/dimmer light situations
  tsl.setGain(gainSetting);

  // Changing the integration time gives you a longer time over which to sense light
  // longer timelines are slower, but are good in very low light situtations!
  tsl.setTiming(timeSetting);
}

// calibrate TSL2591 gain and integration time
bool calibrateTSL2591() {
  if (tsl2591Data.visible < 100) { //Increase GAIN (and INTEGRATIONTIME) if light level too low
    switch (tsl2591Data.gain)
    {
      case TSL2591_GAIN_LOW :
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_MED :
        configureSensorTSL2591(TSL2591_GAIN_HIGH, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_HIGH :
        configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_MAX :
        switch (tsl2591Data.timing)
        {
          case TSL2591_INTEGRATIONTIME_200MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_300MS);
            break;
          case TSL2591_INTEGRATIONTIME_300MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_400MS);
            break;
          case TSL2591_INTEGRATIONTIME_400MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_500MS);
            break;
          case TSL2591_INTEGRATIONTIME_500MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_600MS);
            break;
          case TSL2591_INTEGRATIONTIME_600MS :
            // no higher sensitivity level available
            return false;
            break;
          default:
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_600MS);
            break;
        }
        break;
      default:
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
    }

    // calibration changed
    return true;
  }

  if (tsl2591Data.visible > 30000) { //Decrease GAIN (and INTEGRATIONTIME) if light level too high
    switch (tsl2591Data.gain)
    {
      case TSL2591_GAIN_LOW :
        switch (tsl2591Data.timing)
        {
          case TSL2591_INTEGRATIONTIME_500MS :
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_400MS);
            break;
          case TSL2591_INTEGRATIONTIME_400MS :
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_300MS);
            break;
          case TSL2591_INTEGRATIONTIME_300MS :
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_200MS);
            break;
          case TSL2591_INTEGRATIONTIME_200MS :
            // no higher sensitivity level available
            return false;
            break;

          default:
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_200MS);
            break;
        }
        break;
      case TSL2591_GAIN_MED :
        configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_HIGH :
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_MAX :
        configureSensorTSL2591(TSL2591_GAIN_HIGH, TSL2591_INTEGRATIONTIME_200MS);
        break;
      default:
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
    }
    // calibraton changed
    return true;
  }

  // no calibration change necessary
  return false;
}

void setup() {
  Serial.begin(SerialSpeed);
  Wire.begin();
  bme.begin();
  mlx.begin();
 }

void updateBME() {
  float temp(NAN), hum(NAN), pres(NAN);
  BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
  BME280::PresUnit presUnit(BME280::PresUnit_hPa);
  bme.read(pres, temp, hum, tempUnit, presUnit);
  temperature_ambiante_BME = temp;
  pression_locale          = pres+correction_altitude_pression;
  humidite                 = hum;
}

void updateMLX() {

    temperature_ambiante_MLX = mlx.readAmbientTempC();
    temperature_ciel         = mlx.readObjectTempC();
}

void updateTSL2591() {
    tsl.begin();
    // Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum
    tsl2591Data.full    = tsl.getFullLuminosity();
    tsl2591Data.ir      = tsl2591Data.full >> 16;
    tsl2591Data.visible = tsl2591Data.full & 0xFFFF;
    tsl2591Data.lux     = tsl.calculateLux(tsl2591Data.visible, tsl2591Data.ir);
    tsl2591Data.gain    = tsl.getGain();
    tsl2591Data.timing  = tsl.getTiming();

    bool changed = calibrateTSL2591();
    if (changed) updateTSL2591();
}

void loop() {
 
  updateBME();
  updateMLX();
  correction_temperature = (K1 / 100) * (temperature_ambiante_MLX - K2 / 10) + (K3 / 100) * pow((exp (K4 / 1000* temperature_ambiante_MLX)) , (K5 / 100))+CWT;
  temperature_ciel_corrigee = temperature_ciel - correction_temperature;
  dewpoint = ((sqrt(sqrt(sqrt(humidite/100))))*(110+temperature_ambiante_BME))-110;
  //nuages = (temperature_ciel_corrigee - temperature_ciel_clair) *100 / (temperature_ciel_couvert - temperature_ciel_clair);
  if (temperature_ciel_corrigee < temperature_ciel_clair )
  {
    nuages = 0.0;
  }
  else if (temperature_ciel_corrigee > temperature_ciel_couvert)
  {
    nuages = 100.0;
  }
  else
  {
    nuages = map(nuages,-8.0,-0.0,0,100);
  }
  updateTSL2591();
  
    Serial.print("T:");
    Serial.print(temperature_ambiante_BME,1);
    Serial.print(",C:");
    Serial.print(temperature_ciel_corrigee,1);   
    Serial.print(",P:");
    Serial.print(pression_locale,1);
    Serial.print(",H:");
    Serial.print(humidite,1);
    Serial.print(",D:");
    Serial.print(dewpoint,1);
    Serial.print(",L:");
    Serial.print(tsl2591Data.lux,1);
    Serial.print(",N:");
    Serial.println(nuages,0);        
    
 delay(delais);
}

 

Sur le port série on obtient toutes les 5s la chaine suivante:

image.png.6a3ecd53a88ac442552eac02fcfa6bee.png

 

Ensuite sur le driver Ascom:

// TODO fill in this information for your driver, then remove this line!
//
// ASCOM ObservingConditions hardware class for MeteoAstrolivier76
//
// Description:     <To be completed by driver developer>
//
// Implements:    ASCOM ObservingConditions interface version: <To be completed by driver developer>
// Author:        (XXX) Your N. Here <your@email.here>
//

using ASCOM;
using ASCOM.Astrometry;
using ASCOM.Astrometry.AstroUtils;
using ASCOM.Astrometry.NOVAS;
using ASCOM.DeviceInterface;
using ASCOM.LocalServer;
using ASCOM.Utilities;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO.Ports;
using System.Linq.Expressions;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;

namespace ASCOM.MeteoAstrolivier76.ObservingConditions
{
    //
    // TODO Replace the not implemented exceptions with code to implement the function or throw the appropriate ASCOM exception.
    //

    /// <summary>
    /// ASCOM ObservingConditions hardware class for MeteoAstrolivier76.
    /// </summary>
    [HardwareClass()] // Class attribute flag this as a device hardware class that needs to be disposed by the local server when it exits.
    internal static class ObservingConditionsHardware
    {
        // Constants used for Profile persistence
        internal const string comPortProfileName = "COM Port";
        internal const string comPortDefault = "COM10";
        internal const string traceStateProfileName = "Trace Level";
        internal const string traceStateDefault = "true";

        private static string DriverProgId = ""; // ASCOM DeviceID (COM ProgID) for this driver, the value is set by the driver's class initialiser.
        private static string DriverDescription = ""; // The value is set by the driver's class initialiser.
        internal static string comPort; // COM port name (if required)
        private static bool connectedState; // Local server's connected state
        private static bool runOnce = false; // Flag to enable "one-off" activities only to run once.
        internal static Util utilities; // ASCOM Utilities object for use as required
        internal static AstroUtils astroUtilities; // ASCOM AstroUtilities object for use as required
        internal static TraceLogger tl; // Local server's trace logger object for diagnostic log with information that you specify

        private static SerialPort arduinoport;

        private static double temperature;
        private static double skytemperature;
        private static double pression;
        private static double humidity;
        private static double dewpoint;
        private static double skyluminosite;
        private static double cloud;

        /// <summary>
        /// Initializes a new instance of the device Hardware class.
        /// </summary>
        static ObservingConditionsHardware()
        {
            try
            {
                // Create the hardware trace logger in the static initialiser.
                // All other initialisation should go in the InitialiseHardware method.
                tl = new TraceLogger("", "MeteoAstrolivier76.Hardware");

                // DriverProgId has to be set here because it used by ReadProfile to get the TraceState flag.
                DriverProgId = ObservingConditions.DriverProgId; // Get this device's ProgID so that it can be used to read the Profile configuration values

                // ReadProfile has to go here before anything is written to the log because it loads the TraceLogger enable / disable state.
                ReadProfile(); // Read device configuration from the ASCOM Profile store, including the trace state

                LogMessage("ObservingConditionsHardware", $"Static initialiser completed.");
            }
            catch (Exception ex)
            {
                try { LogMessage("ObservingConditionsHardware", $"Initialisation exception: {ex}"); } catch { }
                MessageBox.Show($"{ex.Message}", "Exception creating ASCOM.MeteoAstrolivier76.ObservingConditions", MessageBoxButtons.OK, MessageBoxIcon.Error);
                throw;
            }
        }

        /// <summary>
        /// Place device initialisation code here
        /// </summary>
        /// <remarks>Called every time a new instance of the driver is created.</remarks>
        internal static void InitialiseHardware()
        {
            // This method will be called every time a new ASCOM client loads your driver
            LogMessage("InitialiseHardware", $"Start.");

            // Make sure that "one off" activities are only undertaken once
            if (runOnce == false)
            {
                LogMessage("InitialiseHardware", $"Starting one-off initialisation.");

                DriverDescription = ObservingConditions.DriverDescription; // Get this device's Chooser description

                LogMessage("InitialiseHardware", $"ProgID: {DriverProgId}, Description: {DriverDescription}");

                connectedState = false; // Initialise connected to false
                utilities = new Util(); //Initialise ASCOM Utilities object
                astroUtilities = new AstroUtils(); // Initialise ASCOM Astronomy Utilities object

                LogMessage("InitialiseHardware", "Completed basic initialisation");

                // Add your own "one off" device initialisation here e.g. validating existence of hardware and setting up communications

                LogMessage("InitialiseHardware", $"One-off initialisation complete.");
                runOnce = true; // Set the flag to ensure that this code is not run again
            }
        }

        // PUBLIC COM INTERFACE IObservingConditions IMPLEMENTATION

        #region Common properties and methods.

        /// <summary>
        /// Displays the Setup Dialogue form.
        /// If the user clicks the OK button to dismiss the form, then
        /// the new settings are saved, otherwise the old values are reloaded.
        /// THIS IS THE ONLY PLACE WHERE SHOWING USER INTERFACE IS ALLOWED!
        /// </summary>
        public static void SetupDialog()
        {
            // Don't permit the setup dialogue if already connected
            if (IsConnected)
                MessageBox.Show("Already connected, just press OK");

            using (SetupDialogForm F = new SetupDialogForm(tl))
            {
                var result = F.ShowDialog();
                if (result == DialogResult.OK)
                {
                    WriteProfile(); // Persist device configuration values to the ASCOM Profile store
                }
            }
        }

        /// <summary>Returns the list of custom action names supported by this driver.</summary>
        /// <value>An ArrayList of strings (SafeArray collection) containing the names of supported actions.</value>
        public static ArrayList SupportedActions
        {
            get
            {
                LogMessage("SupportedActions Get", "Returning empty ArrayList");
                return new ArrayList();
            }
        }

        /// <summary>Invokes the specified device-specific custom action.</summary>
        /// <param name="ActionName">A well known name agreed by interested parties that represents the action to be carried out.</param>
        /// <param name="ActionParameters">List of required parameters or an <see cref="String.Empty">Empty String</see> if none are required.</param>
        /// <returns>A string response. The meaning of returned strings is set by the driver author.
        /// <para>Suppose filter wheels start to appear with automatic wheel changers; new actions could be <c>QueryWheels</c> and <c>SelectWheel</c>. The former returning a formatted list
        /// of wheel names and the second taking a wheel name and making the change, returning appropriate values to indicate success or failure.</para>
        /// </returns>
        public static string Action(string actionName, string actionParameters)
        {
            LogMessage("Action", $"Action {actionName}, parameters {actionParameters} is not implemented");
            throw new ActionNotImplementedException("Action " + actionName + " is not implemented by this driver");
        }

        /// <summary>
        /// Transmits an arbitrary string to the device and does not wait for a response.
        /// Optionally, protocol framing characters may be added to the string before transmission.
        /// </summary>
        /// <param name="Command">The literal command string to be transmitted.</param>
        /// <param name="Raw">
        /// if set to <c>true</c> the string is transmitted 'as-is'.
        /// If set to <c>false</c> then protocol framing characters may be added prior to transmission.
        /// </param>
        public static void CommandBlind(string command, bool raw)
        {
            CheckConnected("CommandBlind");
            // TODO The optional CommandBlind method should either be implemented OR throw a MethodNotImplementedException
            // If implemented, CommandBlind must send the supplied command to the mount and return immediately without waiting for a response

            throw new MethodNotImplementedException($"CommandBlind - Command:{command}, Raw: {raw}.");
        }

        /// <summary>
        /// Transmits an arbitrary string to the device and waits for a boolean response.
        /// Optionally, protocol framing characters may be added to the string before transmission.
        /// </summary>
        /// <param name="Command">The literal command string to be transmitted.</param>
        /// <param name="Raw">
        /// if set to <c>true</c> the string is transmitted 'as-is'.
        /// If set to <c>false</c> then protocol framing characters may be added prior to transmission.
        /// </param>
        /// <returns>
        /// Returns the interpreted boolean response received from the device.
        /// </returns>
        public static bool CommandBool(string command, bool raw)
        {
            CheckConnected("CommandBool");
            // TODO The optional CommandBool method should either be implemented OR throw a MethodNotImplementedException
            // If implemented, CommandBool must send the supplied command to the mount, wait for a response and parse this to return a True or False value

            throw new MethodNotImplementedException($"CommandBool - Command:{command}, Raw: {raw}.");
        }

        /// <summary>
        /// Transmits an arbitrary string to the device and waits for a string response.
        /// Optionally, protocol framing characters may be added to the string before transmission.
        /// </summary>
        /// <param name="Command">The literal command string to be transmitted.</param>
        /// <param name="Raw">
        /// if set to <c>true</c> the string is transmitted 'as-is'.
        /// If set to <c>false</c> then protocol framing characters may be added prior to transmission.
        /// </param>
        /// <returns>
        /// Returns the string response received from the device.
        /// </returns>
        public static string CommandString(string command, bool raw)
        {
            CheckConnected("CommandString");
            // TODO The optional CommandString method should either be implemented OR throw a MethodNotImplementedException
            // If implemented, CommandString must send the supplied command to the mount and wait for a response before returning this to the client

            throw new MethodNotImplementedException($"CommandString - Command:{command}, Raw: {raw}.");
        }

        /// <summary>
        /// Deterministically release both managed and unmanaged resources that are used by this class.
        /// </summary>
        /// <remarks>
        /// TODO: Release any managed or unmanaged resources that are used in this class.
        /// 
        /// Do not call this method from the Dispose method in your driver class.
        ///
        /// This is because this hardware class is decorated with the <see cref="HardwareClassAttribute"/> attribute and this Dispose() method will be called 
        /// automatically by the  local server executable when it is irretrievably shutting down. This gives you the opportunity to release managed and unmanaged 
        /// resources in a timely fashion and avoid any time delay between local server close down and garbage collection by the .NET runtime.
        ///
        /// For the same reason, do not call the SharedResources.Dispose() method from this method. Any resources used in the static shared resources class
        /// itself should be released in the SharedResources.Dispose() method as usual. The SharedResources.Dispose() method will be called automatically 
        /// by the local server just before it shuts down.
        /// 
        /// </remarks>
        public static void Dispose()
        {
            try { LogMessage("Dispose", $"Disposing of assets and closing down."); } catch { }

            try
            {
                // Clean up the trace logger and utility objects
                tl.Enabled = false;
                tl.Dispose();
                tl = null;
            }
            catch { }

            try
            {
                utilities.Dispose();
                utilities = null;
            }
            catch { }

            try
            {
                astroUtilities.Dispose();
                astroUtilities = null;
            }
            catch { }
        }

        public static void ChooseCOMPort()
        {
            using (var portChooser = new ASCOM.Utilities.Chooser())
            {
                portChooser.DeviceType = "ObservingConditions";

                string selectedPort = portChooser.Choose();

                if (selectedPort == null)
                {
                    // L'utilisateur a annulé la sélection du port COM.
                    return;
                }

                // Mettez à jour la variable de port COM avec la sélection de l'utilisateur.
                comPort = selectedPort;
            }
        }

        /// <summary>
        /// Set True to connect to the device hardware. Set False to disconnect from the device hardware.
        /// You can also read the property to check whether it is connected. This reports the current hardware state.
        /// </summary>
        /// <value><c>true</c> if connected to the hardware; otherwise, <c>false</c>.</value>
        public static bool Connected
        {
            get
            {
                LogMessage("Connected", $"Get {IsConnected}");
                return IsConnected;
            }
            set
            {
                LogMessage("Connected", $"Set {value}");
                if (value == IsConnected)
                    return;

                if (value)
                {
                    LogMessage("Connected Set", $"Connecting to port {comPort}");

                    // TODO insert connect to the device code here
                    arduinoport = new SerialPort(comPort, 9600);//Set your board COM
                    arduinoport.DataReceived += new SerialDataReceivedEventHandler(arduinoport_DataReceived);
                    arduinoport.Open();
                    connectedState = true;
                }
                else
                {
                    LogMessage("Connected Set", $"Disconnecting from port {comPort}");

                    // TODO insert disconnect from the device code here

                    connectedState = false;
                    arduinoport.Close();
                }
            }
        }
        private static void arduinoport_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

            //Et là à toi de voir comment manipuler le string pour en sortir tes données, c'est toi qui décide comment c'est mis en forme dans l'arduino.
            string responsearduino = arduinoport.ReadLine();
            string[] values = responsearduino.Split(',');
            if (values.Length == 7 && double.TryParse(values[0].Substring(2), out double temp) && double.TryParse(values[1].Substring(2), out double skyT) && double.TryParse(values[2].Substring(2), out double pres) && double.TryParse(values[3].Substring(2), out double hum) && double.TryParse(values[4].Substring(2), out double dew) && double.TryParse(values[5].Substring(2), out double skyL) && double.TryParse(values[6].Substring(2), out double cloudy))
            {
                temperature = temp;
                skytemperature = skyT;
                pression = pres;
                humidity = hum;
                dewpoint = dew;
                skyluminosite = skyL;
                cloud = cloudy; 
            }
            else
            {
                temperature = 0;
                skytemperature = 0;
                pression = 0;
                humidity = 0;
                dewpoint = 0;
                skyluminosite = 0;
                cloud = 0;
            }
        }
        /// <summary>
        /// Returns a description of the device, such as manufacturer and model number. Any ASCII characters may be used.
        /// </summary>
        /// <value>The description.</value>
        public static string Description
        {
            // TODO customise this device description if required
            get
            {
                LogMessage("Description Get", DriverDescription);
                return DriverDescription;
            }
        }

        /// <summary>
        /// Descriptive and version information about this ASCOM driver.
        /// </summary>
        public static string DriverInfo
        {
            get
            {
                Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
                // TODO customise this driver description if required
                string driverInfo = $"Information about the driver itself. Version: {version.Major}.{version.Minor}";
                LogMessage("DriverInfo Get", driverInfo);
                return driverInfo;
            }
        }

        /// <summary>
        /// A string containing only the major and minor version of the driver formatted as 'm.n'.
        /// </summary>
        public static string DriverVersion
        {
            get
            {
                Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
                string driverVersion = $"{version.Major}.{version.Minor}";
                LogMessage("DriverVersion Get", driverVersion);
                return driverVersion;
            }
        }

        /// <summary>
        /// The interface version number that this device supports.
        /// </summary>
        public static short InterfaceVersion
        {
            // set by the driver wizard
            get
            {
                LogMessage("InterfaceVersion Get", "1");
                return Convert.ToInt16("1");
            }
        }

        /// <summary>
        /// The short name of the driver, for display purposes
        /// </summary>
        public static string Name
        {
            // TODO customise this device name as required
            get
            {
                string name = "Short driver name - please customise";
                LogMessage("Name Get", name);
                return name;
            }
        }

        #endregion

        #region IObservingConditions Implementation

        // Time and wind speed values
        private static Dictionary<DateTime, double> winds = new Dictionary<DateTime, double>();

        /// <summary>
        /// Gets and sets the time period over which observations wil be averaged
        /// </summary>
        internal static double AveragePeriod
        {
            get
            {
                LogMessage("AveragePeriod", "get - 0");
                return 0;
            }
            set
            {
                LogMessage("AveragePeriod Set", value.ToString());
                if (value != 0)
                    throw new InvalidValueException("AveragePeriod", value.ToString(), "0 only");
            }
        }

        /// <summary>
        /// Amount of sky obscured by cloud
        /// </summary>
        internal static double CloudCover
        {
            get { return cloud; }
            private set { cloud = value; }
        }

        /// <summary>
        /// Atmospheric dew point at the observatory in deg C
        /// </summary>
        internal static double DewPoint
        {
            get { return dewpoint; }
            private set { dewpoint = value; }
        }

        /// <summary>
        /// Atmospheric relative humidity at the observatory in percent
        /// </summary>
        internal static double Humidity
        {
            get { return humidity; }
            private set { humidity = value; }
        }

        /// <summary>
        /// Atmospheric pressure at the observatory in hectoPascals (mB)
        /// </summary>
        internal static double Pressure
        {
            get { return pression; }
            private set { pression = value; }
        }

        /// <summary>
        /// Rain rate at the observatory
        /// </summary>
        internal static double RainRate
        {
            get
            {
                LogMessage("RainRate", "get - not implemented");
                throw new PropertyNotImplementedException("RainRate", false);
            }
        }

        /// <summary>
        /// Forces the driver to immediately query its attached hardware to refresh sensor
        /// values
        /// </summary>
        internal static void Refresh()
        {
            throw new MethodNotImplementedException();
        }

        /// <summary>
        /// Provides a description of the sensor providing the requested property
        /// </summary>
        /// <param name="propertyName">Name of the property whose sensor description is required</param>
        /// <returns>The sensor description string</returns>
        internal static string SensorDescription(string propertyName)
        {
            switch (propertyName.Trim().ToLowerInvariant())
            {
                case "averageperiod":
                    return "Average period in hours, immediate values are only available";
                case "cloudcover":
                case "dewpoint":
                case "humidity":
                case "pressure":
                case "rainrate":
                case "skybrightness":
                case "skyquality":
                case "skytemperature":
                case "starfwhm":
                case "temperature":
                case "winddirection":
                case "windgust":
                case "windspeed":
                    // Throw an exception on the properties that are not implemented
                    LogMessage("SensorDescription", $"Property {propertyName} is not implemented");
                    throw new MethodNotImplementedException($"SensorDescription - Property {propertyName} is not implemented");
                default:
                    LogMessage("SensorDescription", $"Invalid sensor name: {propertyName}");
                    throw new InvalidValueException($"SensorDescription - Invalid property name: {propertyName}");
            }
        }

        /// <summary>
        /// Sky brightness at the observatory
        /// </summary>
        internal static double SkyBrightness
        {
            get { return skyluminosite; }
            private set { skyluminosite = value; }
        }

        /// <summary>
        /// Sky quality at the observatory
        /// </summary>
        internal static double SkyQuality
        {
            get
            {
                LogMessage("SkyQuality", "get - not implemented");
                throw new PropertyNotImplementedException("SkyQuality", false);
            }
        }

        /// <summary>
        /// Seeing at the observatory
        /// </summary>
        internal static double StarFWHM
        {
            get
            {
                LogMessage("StarFWHM", "get - not implemented");
                throw new PropertyNotImplementedException("StarFWHM", false);
            }
        }

        /// <summary>
        /// Sky temperature at the observatory in deg C
        /// </summary>
        internal static double SkyTemperature
        {
            get { return skytemperature; }
            private set { skytemperature = value; }
        }

        /// <summary>
        /// Temperature at the observatory in deg C
        /// </summary>
        internal static double Temperature
        {
            get { return temperature; }
            private set { temperature = value; }
        }

        /// <summary>
        /// Provides the time since the sensor value was last updated
        /// </summary>
        /// <param name="propertyName">Name of the property whose time since last update Is required</param>
        /// <returns>Time in seconds since the last sensor update for this property</returns>
        internal static double TimeSinceLastUpdate(string propertyName)
        {
            // Test for an empty property name, if found, return the time since the most recent update to any sensor
            if (!string.IsNullOrEmpty(propertyName))
            {
                switch (propertyName.Trim().ToLowerInvariant())
                {
                    // Return the time for properties that are implemented, otherwise fall through to the MethodNotImplementedException
                    case "averageperiod":
                    case "cloudcover":
                    case "dewpoint":
                    case "humidity":
                    case "pressure":
                    case "rainrate":
                    case "skybrightness":
                    case "skyquality":
                    case "skytemperature":
                    case "starfwhm":
                    case "temperature":
                    case "winddirection":
                    case "windgust":
                    case "windspeed":
                        // Throw an exception on the properties that are not implemented
                        LogMessage("TimeSinceLastUpdate", $"Property {propertyName} is not implemented");
                        throw new MethodNotImplementedException($"TimeSinceLastUpdate - Property {propertyName} is not implemented");
                    default:
                        LogMessage("TimeSinceLastUpdate", $"Invalid sensor name: {propertyName}");
                        throw new InvalidValueException($"TimeSinceLastUpdate - Invalid property name: {propertyName}");
                }
            }

            // Return the time since the most recent update to any sensor
            LogMessage("TimeSinceLastUpdate", $"The time since the most recent sensor update is not implemented");
            throw new MethodNotImplementedException("TimeSinceLastUpdate(" + propertyName + ")");
        }

        /// <summary>
        /// Wind direction at the observatory in degrees
        /// </summary>
        internal static double WindDirection
        {
            get
            {
                LogMessage("WindDirection", "get - not implemented");
                throw new PropertyNotImplementedException("WindDirection", false);
            }
        }

        /// <summary>
        /// Peak 3 second wind gust at the observatory over the last 2 minutes in m/s
        /// </summary>
        internal static double WindGust
        {
            get
            {
                LogMessage("WindGust", "get - not implemented");
                throw new PropertyNotImplementedException("WindGust", false);
            }
        }

        /// <summary>
        /// Wind speed at the observatory in m/s
        /// </summary>
        internal static double WindSpeed
        {
            get
            {
                LogMessage("WindSpeed", "get - not implemented");
                throw new PropertyNotImplementedException("WindSpeed", false);
            }
        }

        #endregion

        #region Private methods

        #region Calculate the gust strength as the largest wind recorded over the last two minutes


        private static void UpdateGusts(double speed)
        {
            Dictionary<DateTime, double> newWinds = new Dictionary<DateTime, double>();
            var last = DateTime.Now - TimeSpan.FromMinutes(2);
            winds.Add(DateTime.Now, speed);
            var gust = 0.0;
            foreach (var item in winds)
            {
                if (item.Key > last)
                {
                    newWinds.Add(item.Key, item.Value);
                    if (item.Value > gust)
                        gust = item.Value;
                }
            }
            winds = newWinds;
        }

        #endregion

        #endregion

        #region Private properties and methods
        // Useful methods that can be used as required to help with driver development

        /// <summary>
        /// Returns true if there is a valid connection to the driver hardware
        /// </summary>
        private static bool IsConnected
        {
            get
            {
                // TODO check that the driver hardware connection exists and is connected to the hardware
                return connectedState;
            }
        }

        /// <summary>
        /// Use this function to throw an exception if we aren't connected to the hardware
        /// </summary>
        /// <param name="message"></param>
        private static void CheckConnected(string message)
        {
            if (!IsConnected)
            {
                throw new NotConnectedException(message);
            }
        }

        /// <summary>
        /// Read the device configuration from the ASCOM Profile store
        /// </summary>
        internal static void ReadProfile()
        {
            using (Profile driverProfile = new Profile())
            {
                driverProfile.DeviceType = "ObservingConditions";
                tl.Enabled = Convert.ToBoolean(driverProfile.GetValue(DriverProgId, traceStateProfileName, string.Empty, traceStateDefault));
                comPort = driverProfile.GetValue(DriverProgId, comPortProfileName, string.Empty, comPortDefault);
            }
        }

        /// <summary>
        /// Write the device configuration to the  ASCOM  Profile store
        /// </summary>
        internal static void WriteProfile()
        {
            using (Profile driverProfile = new Profile())
            {
                driverProfile.DeviceType = "ObservingConditions";
                driverProfile.WriteValue(DriverProgId, traceStateProfileName, tl.Enabled.ToString());
                driverProfile.WriteValue(DriverProgId, comPortProfileName, comPort.ToString());
            }
        }

        /// <summary>
        /// Log helper function that takes identifier and message strings
        /// </summary>
        /// <param name="identifier"></param>
        /// <param name="message"></param>
        internal static void LogMessage(string identifier, string message)
        {
            tl.LogMessageCrLf(identifier, message);
        }

        /// <summary>
        /// Log helper function that takes formatted strings and arguments
        /// </summary>
        /// <param name="identifier"></param>
        /// <param name="message"></param>
        /// <param name="args"></param>
        internal static void LogMessage(string identifier, string message, params object[] args)
        {
            var msg = string.Format(message, args);
            LogMessage(identifier, msg);
        }
        #endregion
    }
}

 

Lien vers le commentaire
Partager sur d’autres sites

Posté (modifié)

bonjour @Antiath,

 

je me suis penché hier soir sur mon sujet.

J'ai repris à 0 le driver dans VS 2022 pour ne pas utiliser les templates 2022 mais les anciens de 2019.

Le code est toujours en C# mais le driver ne contient que le fichier ObservingConditions.cs

J'ai ensuité appliqué à la lettre la procédure du ReadMe.

J'ai donc compiler la solution, sans erreur puis j'ai ajouté dans la solution un nouveau projet pour le client.

J'ai ensuite demandé que ce projet soit definit en tant que projet de démarrage.

J'ai recompilé et sans erreur pour les deux.

Bon, je n'ai pas modifieé le client pour y afficher des valeurs pour le moment.

J'ai lancé NINA et mon driver apparait bien dedans.

Je me connecte et cela fonctionne. Bon, normal j'ai aucune données qui s'affiche.

 

J'ai donc repris le code du driver et du firmware arduino.

Pour que ce soit plus simple je demande juste à l'arduino d'envoyer sur le port série avec la commande Serial.println()  toutes les 5s la valeur de la température locale.

 

Dans le driver Ascom j'ai implémenté ton code permettant d'écouter le port série et de traiter la chaine lorsqu'elle est reçue.

 

Je n'ai pas d'érreur dans le code et je compile tout.

Le truc c'est que la valeur la température reste à 0°C en tout temps, valeur de la variable à l'initialisation.

Si je mets 20°C alors NINA laisse afficher 20°C en permanence.

J'ai donc regardé le fichier de debugage et on voit qu'il affiche cette valeur.

Je ne sais pas comment faire afficher la valeur dans le logMessage car celui ci n'accepte visiblement que des chaines et non des double. Il faudrait que je convertir cette valeur pour l'afficher.

 

Bref, à priori le driver tel qu'il est écrit ne tient pas compte de ce qui se passe sur le port série.

 

Aurais tu une idée?

 

Je joins les code en fichier texte car sur la page ca fait beaucoup trop!! et il n'existe plus l'option "masqué" 😕

Merci

ObservingConditionsDriver.cs

Modifié par astrolivier
Lien vers le commentaire
Partager sur d’autres sites

il faut appeler la lecture sur Série ou ta fonction qui lit le port série ici
 

public double Temperature
        {
            get
            {
                return temperature;
                //tl.logMessage("Temperature", temperature);

            }
        }

 

 

Un exemple ci dessous, un peu différent car je récupère les données d'un fichier JSON par une requête http sur la plateforme météo elle même  dans un fichier stocké en local (fonction GetJSON)

 

Public ReadOnly Property Temperature() As Double Implements IObservingConditions.Temperature
    Get
        TL.LogMessage("Temperature", "Get Not implemented")
        'Throw New ASCOM.PropertyNotImplementedException("Temperature", True)
        Dim T = GetJSON("ambient")
        Return T
    End Get
End Property

 

J'appelle une function() GetJson comme tu pourrais appeler ta fonction de lecture du port série.

Modifié par Raphael_OD
Lien vers le commentaire
Partager sur d’autres sites

il y a une heure, Raphael_OD a dit :

J'appelle une function() GetJson comme tu pourrais appeler ta fonction de lecture du port série.

Merci pour le retour.

 

Initialement c'est ce que je comptais faire, mais cela impose de revoir mon code.

en effet dans ce sens là à chaque fonction je dois questionner l'arduino.

Là je pensais plus faire une réception d'une chaine et traiter la chaine ensuite. Une fois chaque valeur scindées je la remettais dans sa variable.

 c'est cette fonction là:

private double temperature;
        private double skytemperature;
        private double pression;
        private double humidity;
        private double dewpoint;
        private double skyluminosite;
        private double cloud;
              .
              .
              .

        public bool Connected
        {
            get
            {
                LogMessage("Connected", "Get {0}", IsConnected);
                return IsConnected;
            }
            set
            {
                tl.LogMessage("Connected", "Set {0}", value);
                if (value == IsConnected)
                    return;

                if (value)
                {
                    connectedState = true;
                    LogMessage("Connected Set", "Connecting to port {0}", comPort);

                    arduinoport = new SerialPort(comPort, 9600);//Set your board COM
                    arduinoport.Open();
                    arduinoport.DataReceived += new SerialDataReceivedEventHandler(arduinoport_DataReceived);


                }
                else
                {
                    connectedState = false;
                    LogMessage("Connected Set", "Disconnecting from port {0}", comPort);

                    arduinoport.Close();
                }
            }
        }
        private void arduinoport_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            
            string reponse  = arduinoport.ReadLine(); 

            string[] values = reponse.Split(',');

            if (values.Length == 6 && double.TryParse(values[0].Substring(2), out double temp) && double.TryParse(values[1].Substring(2), out double skyT)&& double.TryParse(values[2].Substring(2), out double pres)&& double.TryParse(values[3].Substring(2), out double hum)&& double.TryParse(values[4].Substring(2), out double dew)&& double.TryParse(values[5].Substring(2), out double skyL))
            {
                temperature = temp;
                skystemperature = skyT;
                pression = pres;
                humidity = hum;
                dewpoint = dew;
                skyluminosite = skyL;
            }
            else
            {
                temperature = 0;
                skystemperature = 0;
                pression = 0;
                humidity = 0;
                dewpoint = 0;
                skyluminosite = 0;
            }
            

        }

par exemple:

       public double Temperature
        {
            get { return temperature; }
        }

 

Je vais potasser cette reflexion :)

Lien vers le commentaire
Partager sur d’autres sites

Posté (modifié)

@Antiath @Raphael_OD

Bonsoir.

Je me permets de vous resolliciter.

Je vous partage là où j'en suis en espérant que vous vous pourrez m'aider.

 

J'ai donc repris le driver selon les anciens templates mais toujours en C#. Plus de truc local etc...

Je suis donc les recommandations et j'ai crée un client. J'ai ajouté des textbox pour y afficher les valeurs envoyé par le driver. Pour le moment avec le simulateur cela fonctionne comme on peut le voir ici:
image.png.6048d5fe4b6ed0d78ab07179ad79c815.png

 

Bon, le truc c'est que si j'essai avec mon propre driver j'ai une erreur lorsque j'appuis sur Properties afin de sélectionner le port COM:

image.png.7824adfe7037440e7cc7432e521cebe9.png

 

Je ne suis pas encore parvenu à comprendre le pourquoi.

J'ai ensuite continuer sur le code.

 

Bon, pour faire simple, je peux me connecter, à priori l'Arduino se connecte bien mais, car il y a un mais, les valeurs restent toujours à 0 et ce qu'elle que soit la méthode utilisée.

J'ai même réécrit un code arduino pour avoir une fonction de ce genre en testant sur une unique variable. J'ai également volontairement donné une valeur à la variable SkyTemperature.

Cela me permet de voir que le driver retourne bien la valeur que j'ai mise. Par conséquent le problème est bien la valeur provenant de l'Arduino.

Le jour où cela fonctionnera pour la variable j'implémenterais les autre :)

 

petite mise au point sur les modifications du code pour tester ces fonctions:

 

la partie connected

 

 

 

image.png.25e99caa68eb9fda6f7bd39d428e8f23.png

 

        public bool Connected
        {
            get
            {
                tl.LogMessage("Connected Get", IsConnected.ToString());
                return IsConnected;
            }
            set
            {
                tl.LogMessage("Connected Set", value.ToString());
                if (value == IsConnected)
                    return;

                if (value)
                {
                    // try to connect using the port
                    try
                    {
                        serialPort = new Serial();
                        serialPort.PortName = comPort;
                        serialPort.Speed = SerialSpeed.ps57600;
                        serialPort.Connected = true;

                        connectedState = true;
                        tl.LogMessage("Connected Set", "Connecting to port " + comPort);
                    }
                    catch (Exception ex)
                    {
                        // report any error
                        throw new ASCOM.NotConnectedException("Serial port connection error", ex);
                    }
                }
                else
                {
                    connectedState = false;
                    tl.LogMessage("Connected Set", "Disconnecting from port " + comPort);
                    if (serialPort != null && serialPort.Connected)
                        serialPort.Connected = false;
                }
            }
        }

 

et la partie Temperature et SkyTemperature:

image.png.c426742e698c6120ebd170dc46e4513d.png

 

et dans NINA:

image.png.7163698200b71978ba051f72da2d5583.png

 

On voit donc que la variable skytemperature fonctionne mais que la variable demandant une réponse à l'Arduino reste désespérément à 0.

 

Donc voilà où j'en suis, j'avoue être bloqué car après avoir essayé une multitude de code rien à faire...

Depuis l'IDE arduino la commande TL# renvoie bien un xx.xx# ou xx.xx est une valeur de température mesurée part le capteur BME.

 

EDIT: J'ai modifié le code Temperature comme cela:

image.png.fd9eed81cde3c5a0fe2a6e81693f9ef3.png

 

Dans le fichier de log je vois que c'est le Pb qui me revient. Cela indique donc la fonction Double.TryParse est fausse.

 

Comment faire pour savoir pourquoi? Je ne sais pas comment faire pour debuger cela 😕

 

 

EDIT 1: J'ai ajouté des log pour obtenir des valeurs et on voit qu'avant la conversion en double la valeur est bien reçu sur le port série:

image.png.e88dfe75a159c2d223a1d78ef26703a1.png

 

Modifié par astrolivier
ajout d'infos
Lien vers le commentaire
Partager sur d’autres sites

Bon, une reflexion durant la nuit!! Je me suis demandé si la conversion en double ne fonctionnait pas à cause de la décimale e tsurtout s'il n'y avait pas un conflit entre le point et la virugule.

J'ai donc ajouté une conversion au code et maintenant c'est bon, j'ai bien la valeur dans NINA :)

image.png.6f2d6e860ff0b4d96a1c7fb5dbc40168.png

 

Je poursuis donc l'aventure maintenant que je sais comment faire apparaitre les valeurs dans NINA.

Je vais tenter de repasser à mon code initial avec une conversion de toutes les variables :)

 

Je vous tiens au courant.

 

Olivier

  • Merci / Quelle qualité! 1
Lien vers le commentaire
Partager sur d’autres sites

Posté (modifié)

Et bien voilà,

j'ai réimplanté la solution d'écoute du port série.

Le problème venait bien de l'utilisation du point au lieu de la virgule.

Du coup, maintenant tout est fonctionnel.

Me reste juste à savoir maintenant comment utilisé cela en mode safetymonitor.

Je souhaitais avoir une station météo mais j'aurais aimé que celle ci pilote mon futur abris, et notament l'ouverture fermeture en cas de présence de nuages ou non.

Je pourrais assez facilement implanté cela dans le firmware arduino puisqu'il calcul déjà le pourcentage de ciel couvert.

 

Avez vous une idée de comment faire cela?

 

Aussi, nouveau point: maintenant que le driver fonctionne, comment réaliser un executable de ce driver? je sais qu'on parle inno et tout mais les quelques vidéo en anglais que j'ai pu voir ne m'ont pas vraiment aidé 😕

 

merci beaucoup pour l'aide :)

image.png.9f53e6ad227f92a6f1b487df3fbeebf5.png

Modifié par astrolivier
ajout de la vue d'écran
Lien vers le commentaire
Partager sur d’autres sites

1) Ascom driver installer script generator + 2) innosetup,

l'un te génère un script iss , l'autre le fichier de setup en utilisant le fichier script .iss.

Le reste n'est que chemin à indiquer du moment que tu as compilé dans VS en 64 bits ou 32 bits selon ...

Ex.

 Project\bin\x64\releases 

 

L'avantage des fichiers json ou datas stockés quelque part c'est que tu peux les interroger avec n'importe quel driver ASCOM , ObservingConditions , SafetyMonitor, etc ..(sur un réseau interne filaire ou des ESP32 en WIFI)
L'ouverture fermeture de toit ou dôme va dépendre beaucoup du matériel utilisé. Le SafetyMonitor n'attend lui que du Safe ou Unsafe. C'est l'appli NINA qui saura quoi faire en cas de Unsafe ou Safe dans le séquenceur avancé avec un driver Dôme bien sûr.

 

Quel est ton projet d'observatoire ? dans le jardin ?  ou au bout du monde...

 

 

Modifié par Raphael_OD
Lien vers le commentaire
Partager sur d’autres sites

il y a une heure, Raphael_OD a dit :

L'avantage des fichiers json ou datas stockés quelque part c'est que tu peux les interroger avec n'importe quel driver ASCOM , ObservingConditions , SafetyMonitor, etc ..(sur un réseau interne filaire ou des ESP32 en WIFI)

Quel est ton projet d'observatoire ? dans le jardin ?  ou au bout du monde...

 

Et bien mon projet est un abris dans mon jardin.

Disons que je fais plus cela pour m'amuser :)

J'ai commander des ESP32 wifi sur Ali et devraient arrivés dans quelques jours.

 

A terme le but sera biensur d'avoir cette station météo en wifi et certainement avec des fichers json où les drivers pourront aller chercher ce qu'ils veulent.

Mais c'est pour moi déjà plus complexe que ce premier projet assez simple en soit.

C'est mon tout premier driver et le premier objectif atteind pour moi est d'avoir réussi à faire causer l'arduino avec NINA.

la prochaine étape sera de faire la même chose mais en wifi avec l'ESP32 wifi.

l'étape suivante sera de faire ce que tu as fais, à savoir questionner un fichier distant générer par l'ESP32, tout cela dans des drivers que j'aurais bien entendu fais. D'ailleurs, vu que c'est ce que tu as fais, aurais tu la possibilité de partager ton code?  cela m'aiderai beaucoup à la compréhension le moment venu ^^

Par ailleurs un drivers SafetyMonitor est très simple à créer après avoir fait celui ci ^^.

 

il y a une heure, Raphael_OD a dit :

L'ouverture fermeture de toit ou dôme va dépendre beaucoup du matériel utilisé. Le SafetyMonitor n'attend lui que du Safe ou Unsafe. C'est l'appli NINA qui saura quoi faire en cas de Unsafe ou Safe dans le séquenceur avancé avec un driver Dôme bien sûr.

Le driver SafteyMonitor ne permet en effet que de dire si les conditions se dégrade de fermer l'observatoire.

Le projet est un abris de jardin à toi roulant.

Je n'ai pas encore choisi quel driver j'allais utiliser mais le plus simple sera le mieux: ouvrir / fermé avec des fins de courses + une commande manuelle en locale pour les besoins.

Mais comme le driver ObservingConditions dispose du retour quand à la quantité de nuages il est dommage de ne pas pouvoir faire logiciellement un lien entre les deux ^^

Lien vers le commentaire
Partager sur d’autres sites

Nouveau code arduino qui fabrique un JSON.

Je poursuivrais lors de la réception des ESP32.

Il me faudra alors juste faire en sorte d'envoyer le fichier JSON crée sur un Raspbery en mode server (ou une autre manière de le faire plus simplement avec une carte SD sur le nano.

Pour le moment je suis très heureux du résultat :) et surout le principal: Ca fonctionne avec NINA!!

 

// librairies de base
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <ArduinoJson.h>
#include <ArduinoJson.hpp>
//#include <math.h>

#define delais 5000 //temps entre deux maj des valeurs en ms
#define SerialSpeed 9600 // vitesse de communication sur le port série

// utilisation d'un BME280 Velleman WPSE335
#include <BME280I2C.h>
BME280I2C bme;
float temperature_ambiante_BME =0.00;
float pression_locale =0.00;
float correction_altitude_pression = 0.00; //facteur de correction lié à l'altitude locale
float humidite =0.00;
float dewpoint =0.00;
float nuages =0.00;
float lux = 0.00;

// utilisation d'un MLX90614
#include <Adafruit_MLX90614.h>
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
float temperature_ambiante_MLX;
float temperature_ciel;
float correction_temperature;
float temperature_ciel_corrigee;
#define  K1 33.
#define  K2 0.
#define  K3 4.
#define  K4 100.
#define  K5 100.
#define  K6 0.
#define  K7 0.
float CWT; //CWT = Cold Weather correction en cas de basse temperature (<1°C)
// température ciel completement clair
#define temperature_ciel_clair  -8
// température ciel completement couvert
#define temperature_ciel_couvert  0
//Activation treshold for cloudFlag (%)


// utilisation d'un TSL2591
#include <Adafruit_TSL2591.h>
Adafruit_TSL2591 tsl = Adafruit_TSL2591();
struct {
  bool status;
  uint32_t full;
  uint16_t ir;
  uint16_t visible;
  int      gain;
  int      timing;
  float    lux;
} tsl2591Data {false, 0, 0, 0, 0, 0, 0.0};

/**
   tsl.begin() always returns true, hence we need to check the I2C adress
*/
bool isTSL2591Present() {
  Wire.beginTransmission(TSL2591_ADDR);
  byte error = Wire.endTransmission();

  return (error == 0);
}

void configureSensorTSL2591(tsl2591Gain_t gainSetting, tsl2591IntegrationTime_t timeSetting)
{
  // You can change the gain on the fly, to adapt to brighter/dimmer light situations
  tsl.setGain(gainSetting);

  // Changing the integration time gives you a longer time over which to sense light
  // longer timelines are slower, but are good in very low light situtations!
  tsl.setTiming(timeSetting);
}

// calibrate TSL2591 gain and integration time
bool calibrateTSL2591() {
  if (tsl2591Data.visible < 100) { //Increase GAIN (and INTEGRATIONTIME) if light level too low
    switch (tsl2591Data.gain)
    {
      case TSL2591_GAIN_LOW :
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_MED :
        configureSensorTSL2591(TSL2591_GAIN_HIGH, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_HIGH :
        configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_MAX :
        switch (tsl2591Data.timing)
        {
          case TSL2591_INTEGRATIONTIME_200MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_300MS);
            break;
          case TSL2591_INTEGRATIONTIME_300MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_400MS);
            break;
          case TSL2591_INTEGRATIONTIME_400MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_500MS);
            break;
          case TSL2591_INTEGRATIONTIME_500MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_600MS);
            break;
          case TSL2591_INTEGRATIONTIME_600MS :
            // no higher sensitivity level available
            return false;
            break;
          default:
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_600MS);
            break;
        }
        break;
      default:
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
    }

    // calibration changed
    return true;
  }

  if (tsl2591Data.visible > 30000) { //Decrease GAIN (and INTEGRATIONTIME) if light level too high
    switch (tsl2591Data.gain)
    {
      case TSL2591_GAIN_LOW :
        switch (tsl2591Data.timing)
        {
          case TSL2591_INTEGRATIONTIME_500MS :
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_400MS);
            break;
          case TSL2591_INTEGRATIONTIME_400MS :
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_300MS);
            break;
          case TSL2591_INTEGRATIONTIME_300MS :
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_200MS);
            break;
          case TSL2591_INTEGRATIONTIME_200MS :
            // no higher sensitivity level available
            return false;
            break;

          default:
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_200MS);
            break;
        }
        break;
      case TSL2591_GAIN_MED :
        configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_HIGH :
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_MAX :
        configureSensorTSL2591(TSL2591_GAIN_HIGH, TSL2591_INTEGRATIONTIME_200MS);
        break;
      default:
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
    }
    // calibraton changed
    return true;
  }

  // no calibration change necessary
  return false;
}

void setup() {
  Serial.begin(SerialSpeed);
  Wire.begin();
  bme.begin();
  mlx.begin();
 }

void updateBME() {
  float temp(NAN), hum(NAN), pres(NAN);
  BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
  BME280::PresUnit presUnit(BME280::PresUnit_hPa);
  bme.read(pres, temp, hum, tempUnit, presUnit);
  temperature_ambiante_BME = temp;
  pression_locale          = pres+correction_altitude_pression;
  humidite                 = hum;
}

void updateMLX() {

    temperature_ambiante_MLX = mlx.readAmbientTempC();
    temperature_ciel         = mlx.readObjectTempC();
}

void updateTSL2591() {
    tsl.begin();
    // Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum
    tsl2591Data.full    = tsl.getFullLuminosity();
    tsl2591Data.ir      = tsl2591Data.full >> 16;
    tsl2591Data.visible = tsl2591Data.full & 0xFFFF;
    tsl2591Data.lux     = tsl.calculateLux(tsl2591Data.visible, tsl2591Data.ir);
    tsl2591Data.gain    = tsl.getGain();
    tsl2591Data.timing  = tsl.getTiming();

    bool changed = calibrateTSL2591();
    if (changed) updateTSL2591();
}

void loop() 
{
 updateBME();
 updateBME();
 updateMLX();
 correction_temperature = (K1 / 100) * (temperature_ambiante_MLX - K2 / 10) + (K3 / 100) * pow((exp (K4 / 1000* temperature_ambiante_MLX)) , (K5 / 100))+CWT;
 temperature_ciel_corrigee = temperature_ciel - correction_temperature;
 dewpoint = ((sqrt(sqrt(sqrt(humidite/100))))*(110+temperature_ambiante_BME))-110;
 updateTSL2591();
 lux = tsl2591Data.lux;
   if (temperature_ciel_corrigee < temperature_ciel_clair )
  {
    nuages = 0.0;
  }
  else if (temperature_ciel_corrigee > temperature_ciel_couvert)
  {
    nuages = 100.0;
  }
  else
  {
    nuages = map(nuages,-8.0,-0.0,0,100);
  }
 
  // Création d'un objet JSON
  DynamicJsonDocument jsonDoc(200);
  jsonDoc["T"] = temperature_ambiante_BME;
  jsonDoc["C"] = temperature_ciel_corrigee;
  jsonDoc["P"] = pression_locale;
  jsonDoc["H"] = humidite;
  jsonDoc["D"] = dewpoint;
  jsonDoc["L"] = lux;
  jsonDoc["N"] = nuages;

  // Sérialisation de l'objet JSON dans le format spécifié
  String jsonString = "T:" + String(temperature_ambiante_BME, 2) +
                      "|C:" + String(temperature_ciel_corrigee, 2) +
                      "|P:" + String(pression_locale, 2) +
                      "|H:" + String(humidite, 2) +
                      "|D:" + String(dewpoint, 2) +
                      "|L:" + String(lux, 2) +
                      "|N:" + String(nuages, 2);

  // Affichage sur le moniteur série
  Serial.println(jsonString);

  delay(delais);

}

C'est certainement pas le code le plus compliqué ni le meilleur par rapport à d'autres que l'on peut trouver mais j'en suis ravi!!

Cela m'a permis de  démystifier la création d'un driver ascom.

Je vais compiler ce firmware en l'état pour l'installer sur une autre machine et voir si cela fonctionne comme attendu. Ce sera une étape de plus! 

 

 

Lien vers le commentaire
Partager sur d’autres sites

Bonjour à tous,

@Raphael_OD je me permet de te soliciter.

J'ai entrepris de faire le firmware arduino pour l'envoyer dans l'ESP32 dès son arrivé chez moi d'ici demain :)

Je poste donc ici le code pour l'ESP, le driver ASCOM n'étant pas encore modifié pour faire la requete sur l'ESP32.

Donc le principe du firmware est le suivant:

On effectue les mesure tous les X délais choisis au début du code.

On crée un 1er fichier JSON (jsonASCOM) qui comprend l'ensemble des valeurs afin de fournir la chaine au driver ASCOM.

Ce fichier est réécrit tous les x délais.

On crée un 2ème fichier JSON (JsonMETEO) qui comprends les données météo mais ui eux serviront plus tard dans la conception d'une petite interface (au cas où plus tard....)

On crée un 3eme fichier json(JsonIsSafe) qui sert à un futur driver ASCOM de type SafetyMonitor. 

 

Pour un premier jet qu'en penses tu?

 

le code:

// librairies de base
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <ArduinoJson.h>
#include <ArduinoJson.hpp>
#include <SPIFFS.h>
#include <ESPAsyncWebServer.h>
AsyncWebServer server(80);

const char* ssid = "Votre_SSID";  // Remplacez "Votre_SSID" par le nom de votre réseau WiFi
const char* password = "Votre_Mot_de_Passe";  // Remplacez "Votre_Mot_de_Passe" par le mot de passe de votre réseau WiFi

#define delais 5000 //temps entre deux maj des valeurs en ms
#define SerialSpeed 115200 // vitesse de communication sur le port série

// utilisation d'un BME280 Velleman WPSE335
#include <BME280I2C.h>
BME280I2C bme;
float temperature_ambiante_BME =0.00;
float pression_locale =0.00;
float correction_altitude_pression = 0.00; //facteur de correction lié à l'altitude locale
float humidite =0.00;
float dewpoint =0.00;
float nuages =0.00;
float lux = 0.00;
int Safe = 0;

// utilisation d'un MLX90614
#include <Adafruit_MLX90614.h>
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
float temperature_ambiante_MLX;
float temperature_ciel;
float correction_temperature;
float temperature_ciel_corrigee;
#define  K1 33.
#define  K2 0.
#define  K3 4.
#define  K4 100.
#define  K5 100.
#define  K6 0.
#define  K7 0.
float CWT; //CWT = Cold Weather correction en cas de basse temperature (<1°C)
// température ciel completement clair
#define temperature_ciel_clair  -8
// température ciel completement couvert
#define temperature_ciel_couvert  0
//Activation treshold for cloudFlag (%)

// utilisation d'un TSL2591
#include <Adafruit_TSL2591.h>
Adafruit_TSL2591 tsl = Adafruit_TSL2591();
struct {
  bool status;
  uint32_t full;
  uint16_t ir;
  uint16_t visible;
  int      gain;
  int      timing;
  float    lux;
} tsl2591Data {false, 0, 0, 0, 0, 0, 0.0};

/**
   tsl.begin() always returns true, hence we need to check the I2C adress
*/
bool isTSL2591Present() {
  Wire.beginTransmission(TSL2591_ADDR);
  byte error = Wire.endTransmission();

  return (error == 0);
}

void configureSensorTSL2591(tsl2591Gain_t gainSetting, tsl2591IntegrationTime_t timeSetting)
{
  // You can change the gain on the fly, to adapt to brighter/dimmer light situations
  tsl.setGain(gainSetting);

  // Changing the integration time gives you a longer time over which to sense light
  // longer timelines are slower, but are good in very low light situtations!
  tsl.setTiming(timeSetting);
}

// calibrate TSL2591 gain and integration time
bool calibrateTSL2591() {
  if (tsl2591Data.visible < 100) { //Increase GAIN (and INTEGRATIONTIME) if light level too low
    switch (tsl2591Data.gain)
    {
      case TSL2591_GAIN_LOW :
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_MED :
        configureSensorTSL2591(TSL2591_GAIN_HIGH, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_HIGH :
        configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_MAX :
        switch (tsl2591Data.timing)
        {
          case TSL2591_INTEGRATIONTIME_200MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_300MS);
            break;
          case TSL2591_INTEGRATIONTIME_300MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_400MS);
            break;
          case TSL2591_INTEGRATIONTIME_400MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_500MS);
            break;
          case TSL2591_INTEGRATIONTIME_500MS :
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_600MS);
            break;
          case TSL2591_INTEGRATIONTIME_600MS :
            // no higher sensitivity level available
            return false;
            break;
          default:
            configureSensorTSL2591(TSL2591_GAIN_MAX, TSL2591_INTEGRATIONTIME_600MS);
            break;
        }
        break;
      default:
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
    }

    // calibration changed
    return true;
  }

  if (tsl2591Data.visible > 30000) { //Decrease GAIN (and INTEGRATIONTIME) if light level too high
    switch (tsl2591Data.gain)
    {
      case TSL2591_GAIN_LOW :
        switch (tsl2591Data.timing)
        {
          case TSL2591_INTEGRATIONTIME_500MS :
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_400MS);
            break;
          case TSL2591_INTEGRATIONTIME_400MS :
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_300MS);
            break;
          case TSL2591_INTEGRATIONTIME_300MS :
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_200MS);
            break;
          case TSL2591_INTEGRATIONTIME_200MS :
            // no higher sensitivity level available
            return false;
            break;

          default:
            configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_200MS);
            break;
        }
        break;
      case TSL2591_GAIN_MED :
        configureSensorTSL2591(TSL2591_GAIN_LOW, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_HIGH :
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
      case TSL2591_GAIN_MAX :
        configureSensorTSL2591(TSL2591_GAIN_HIGH, TSL2591_INTEGRATIONTIME_200MS);
        break;
      default:
        configureSensorTSL2591(TSL2591_GAIN_MED, TSL2591_INTEGRATIONTIME_200MS);
        break;
    }
    // calibraton changed
    return true;
  }

  // no calibration change necessary
  return false;
}

void setup() {
  Serial.begin(SerialSpeed);
  Wire.begin();
  bme.begin();
  mlx.begin();
    if(!SPIFFS.begin(true)) {
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }
 // Connexion au réseau WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connexion au WiFi en cours...");
  }
  Serial.println("Connecté au réseau WiFi");

  if (!SPIFFS.begin(true)) {
    Serial.println("Une erreur s'est produite lors du montage de SPIFFS");
    return;
  }

  // Serveur web
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    File file = SPIFFS.open("/data.json", "r");
    if(file){
      request->send(SPIFFS, "/data.json", String(), true);
      file.close();
    } else {
      request->send(404);
    }
  });
  server.begin();
}

void updateBME() {
  float temp(NAN), hum(NAN), pres(NAN);
  BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
  BME280::PresUnit presUnit(BME280::PresUnit_hPa);
  bme.read(pres, temp, hum, tempUnit, presUnit);
  temperature_ambiante_BME = temp;
  pression_locale          = pres+correction_altitude_pression;
  humidite                 = hum;
}

void updateMLX() {

    temperature_ambiante_MLX = mlx.readAmbientTempC();
    temperature_ciel         = mlx.readObjectTempC();
}

void updateTSL2591() {
    tsl.begin();
    // Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum
    tsl2591Data.full    = tsl.getFullLuminosity();
    tsl2591Data.ir      = tsl2591Data.full >> 16;
    tsl2591Data.visible = tsl2591Data.full & 0xFFFF;
    tsl2591Data.lux     = tsl.calculateLux(tsl2591Data.visible, tsl2591Data.ir);
    tsl2591Data.gain    = tsl.getGain();
    tsl2591Data.timing  = tsl.getTiming();

    bool changed = calibrateTSL2591();
    if (changed) updateTSL2591();
}

void loop()
{
 updateBME();
 updateBME();
 updateMLX();
 correction_temperature = (K1 / 100) * (temperature_ambiante_MLX - K2 / 10) + (K3 / 100) * pow((exp (K4 / 1000* temperature_ambiante_MLX)) , (K5 / 100))+CWT;
 temperature_ciel_corrigee = temperature_ciel - correction_temperature;
 dewpoint = ((sqrt(sqrt(sqrt(humidite/100))))*(110+temperature_ambiante_BME))-110;
 updateTSL2591();
 lux = tsl2591Data.lux;
  if (temperature_ciel_corrigee < temperature_ciel_clair )
  {
    nuages = 0.0;
    Safe = 1;
  }
  else if (temperature_ciel_corrigee > temperature_ciel_couvert)
  {
    nuages = 100.0;
    Safe = 0;
  }
  else
  {
    nuages = map(nuages,-8.0,-0.0,0,100);
    if(nuages <= 25)
    {
      Safe = 1;
    }
    else
    {
      Safe = 0;
    }
  }
 
  // Création d'un objet JSON
  DynamicJsonDocument jsonMeteo(2000000);
  jsonMeteo["T"] = temperature_ambiante_BME;
  jsonMeteo["C"] = temperature_ciel_corrigee;
  jsonMeteo["P"] = pression_locale;
  jsonMeteo["H"] = humidite;
  jsonMeteo["D"] = dewpoint;
  jsonMeteo["L"] = lux;
  jsonMeteo["N"] = nuages;

 // Sérialisation de l'objet JSON dans une chaîne de caractères
  String jsonStringMeteo;
  serializeJson(jsonMeteo, jsonStringMeteo);

  // Affichage sur le moniteur série
  Serial.println(jsonStringMeteo);

  // Ouvrir le fichier "DataMeteo.json" en mode écriture (efface le contenu existant)
  File fileMeteo = SPIFFS.open("/DataMeteo.json", "a");
  if (!fileMeteo) {
    Serial.println("Failed to open DataMeteo.json for writing");
    return;
  }

  // Formater les données dans le fichier "DataMeteo.json"
  fileMeteo.print("C:");
  fileMeteo.print(temperature_ciel_corrigee, 2);
  fileMeteo.print("|P:");
  fileMeteo.print(pression_locale, 2);
  fileMeteo.print("|H:");
  fileMeteo.print(humidite, 2);
  fileMeteo.print("|D:");
  fileMeteo.print(dewpoint, 2);
  fileMeteo.print("|L:");
  fileMeteo.print(lux, 2);
  fileMeteo.print("|N:");
  fileMeteo.print(nuages, 2);

  // Fermer le fichier
  fileMeteo.close();

  // Création d'un objet JSON
  DynamicJsonDocument jsonASCOM(200);
  jsonASCOM["T"] = temperature_ambiante_BME;
  jsonASCOM["C"] = temperature_ciel_corrigee;
  jsonASCOM["P"] = pression_locale;
  jsonASCOM["H"] = humidite;
  jsonASCOM["D"] = dewpoint;
  jsonASCOM["L"] = lux;
  jsonASCOM["N"] = nuages;

 // Sérialisation de l'objet JSON dans une chaîne de caractères
  String jsonStringASCOM;
  serializeJson(jsonASCOM, jsonStringASCOM);

  // Affichage sur le moniteur série
  Serial.println(jsonStringASCOM);

  // Ouvrir le fichier "DataMeteo.json" en mode écriture (efface le contenu existant)
  File fileASCOM = SPIFFS.open("/DataASCOM.json", "w");
  if (!fileASCOM) {
    Serial.println("Failed to open DataASCOM.json for writing");
    return;
  }

  // Formater les données dans le fichier "DataMeteo.json"
  fileASCOM.print("C:");
  fileASCOM.print(temperature_ciel_corrigee, 2);
  fileASCOM.print("|P:");
  fileASCOM.print(pression_locale, 2);
  fileASCOM.print("|H:");
  fileASCOM.print(humidite, 2);
  fileASCOM.print("|D:");
  fileASCOM.print(dewpoint, 2);
  fileASCOM.print("|L:");
  fileASCOM.print(lux, 2);
  fileASCOM.print("|N:");
  fileASCOM.print(nuages, 2);

  // Fermer le fichier
  fileASCOM.close();

  // Création d'un objet JSON pour le fichier "IsSafe.json"
  DynamicJsonDocument jsonIsSafe(200);
  jsonIsSafe["T"] = Safe;

  // Ouvrir le fichier "IsSafe.json" en mode écriture (efface le contenu existant)
  File fileIsSafe = SPIFFS.open("/IsSafe.json", "w");
  if (!fileIsSafe) {
    Serial.println("Failed to open IsSafe.json for writing");
    return;
  }

  // Sérialisation de l'objet JSON dans le fichier "IsSafe.json"
  serializeJson(jsonIsSafe, fileIsSafe);
  fileIsSafe.println();
  fileIsSafe.close();

  delay(delais);

}
Lien vers le commentaire
Partager sur d’autres sites

  • En ligne récemment   0 membre est en ligne

    • Aucun utilisateur enregistré regarde cette page.
×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer.