Navigation

    • Register
    • Login
    • OpenHardware.io
    • Categories
    • Recent
    • Tags
    • Popular
    1. Home
    2. lrtsenar
    3. Best
    • Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Best
    • Groups

    Best posts made by lrtsenar

    • Device library

      Hi all,

      In order to create devices (relay, button, dallas temperature, and more in the future) in a simple way, I have developped objects. My library compiles fine but I have not yet tested it because i'm waiting from China my Ardino pro mini order 😞

      I have added a preprocessor definition called "MAP" in order to use or not the standard STL C++ library. It grows the code around 5% but you can decide to not use it (which is the default choice).
      Let me share my work and tell me what do you think about it.

      Device.h

      #pragma once
      
      //#define MAP
      #ifdef MAP
      #include <StandardCplusplus.h>
      #include <map>
      #endif
      // CButton
      #include <MyMessage.h>
      #include <Bounce2.h>
      // Dallas temperature
      #include <DallasTemperature.h>
      #include <OneWire.h>
      #include "ElapsedTime.h"
      
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      #define RELAY_ON 0      // GPIO value to write to turn on attached relay
      #define RELAY_OFF 1     // GPIO value to write to turn off attached relay
      
      MySensor* g_pGW;
      #define TheSensor g_pGW
      
      class CDevice;
      #ifdef MAP
      typedef std::map<uint8_t/* id */, CDevice*> MapOfDevice;
      MapOfDevice g_deviceMap;
      #else
      #define DECLARE_NBOFDEVICE(nb) CDevice* g_deviceMap[nb];
      extern CDevice* g_deviceMap[];
      #endif
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      class CDevice
      {
      public:
          CDevice(uint8_t id, uint8_t pin, int state=0)
              : m_id(id)
              , m_pin(pin)
              , m_state(state)
          {
              g_deviceMap[m_id] = this;
      #ifdef DEBUG
              Serial.print("CDevice() id="); Serial.print(m_id);
      #endif
          }
          virtual bool getState() { return m_state; }                 // generic behavior
          virtual void setState(bool bState) { m_state = bState; }    // generic behavior
          virtual void checkChange() {};                              // used in some devices
      
      protected:
          uint8_t     m_id;
          uint8_t     m_pin;
          int         m_state;
      };
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      class CRelay : public CDevice
      {
      public:
          CRelay(uint8_t id, uint8_t pin, bool bActiveAtStart, bool bPersistent)
              : CDevice(id, pin, RELAY_OFF)
              , m_bPersistent(bPersistent)
          {
              g_pGW->present(m_id, S_LIGHT);
              digitalWrite(m_pin, bActiveAtStart ? RELAY_ON : RELAY_OFF);  // force value to be written before setting pin mode
              pinMode(m_pin, OUTPUT);
              if (m_bPersistent)
              {
                  m_state = g_pGW->loadState(m_id);   // last known state from previous run
                  digitalWrite(m_pin, m_state);
              }
          }
      
          void setState(bool bOn)
          {
              m_state = bOn ? RELAY_ON : RELAY_OFF;
              digitalWrite(m_pin, m_state);
              if (m_bPersistent)
              {
                  g_pGW->saveState(m_id, m_state);
              }
      #ifdef DEBUG
              Serial.print("CRelay::set id="); Serial.print(m_id);
              Serial.print(", new status=");   Serial.println(m_state);
      #endif
          }
      
          bool getState() { return m_state ? RELAY_ON : RELAY_OFF; }
      
      protected:
          bool        m_bPersistent;
      };
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      class CButton : public CDevice, public MyMessage, public Bounce
      {
      public:
          CButton(uint8_t id, uint8_t pin, uint8_t linkedId/*relayId*/)
              : CDevice(id, pin)
              , MyMessage(linkedId, V_LIGHT)
              , m_linkedId(linkedId)
          {
              pinMode(m_pin, INPUT);
              digitalWrite(m_pin, HIGH);  // internal pull-up
              attach(m_pin);              // Bounce class
              interval(5);                // Bounce class
          };
      
          // should be called periodically in order to check if button is pressed
          virtual void checkChange()
          {
              update();                   // Bounce class
              int iVal = read();          // Bounce class
              if (iVal != m_state)
              {
                  g_pGW->send(set(g_deviceMap[m_linkedId]->getState() ? false : true), true);    // change value
                  m_state = iVal;
              }
          }
      
      protected:
          uint8_t m_linkedId; // Id with which device (button) is associated
      };
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      class CDallasT : public CDevice, public MyMessage
      {
      public:
          // period : minimum allowed time between two request of temperature
          CDallasT(uint8_t id, uint8_t pin, uint32_t period)
              : CDevice(id, pin)
              , MyMessage(id, V_TEMP)
              , m_oneWire(pin)
              , m_dallasT(NULL)
              , m_etRequest(period)
              , m_etRetrieve(0, false, false) // don't care 2nd param, object started disabled
          {
              m_dallasT.setOneWire(&m_oneWire);
              m_dallasT.setWaitForConversion(false);  // requestTemperatures() will not block current thread
              g_pGW->present(m_id, S_TEMP);
      
              int16_t conversionTime = m_dallasT.millisToWaitForConversion(m_dallasT.getResolution());
              m_etRetrieve.setDelay(conversionTime);
          }
      
          // shoud be called periodically in order to check if temperature has to be measured
          virtual void checkChange()
          {
              if (m_etRequest.isElapsed())
              {
                  m_dallasT.requestTemperatures();    // request temperature from Dallas sensor
                  m_etRetrieve.start();               // 'wait' for end of temperature sampling
                  m_etRequest.start();                // 'wait' for next request
              }
      
              if (m_etRetrieve.isElapsed())             // wait for end of conversion
              {
                  // fetch and round temperature to one decimal
                  float tp = g_pGW->getConfig().isMetric
                           ? m_dallasT.getTempCByIndex(m_id) : m_dallasT.getTempFByIndex(m_id);
                  tp = static_cast<float>(static_cast<int>(tp * 10.)) / 10.;
      
                  if ((tp != m_fTempPrev) && (tp != -127.00) && (tp != 85.00))
                  {
                      g_pGW->send(setSensor(m_id).set(tp, 1));
                      m_fTempPrev = tp;                     // Save new temperature for next compare
                  }
                  m_etRetrieve.disable(); // once temperature is retrieved, wait for next request to retrieve again
              }
          }
      
      protected:
          OneWire             m_oneWire;
          DallasTemperature   m_dallasT;
          float               m_fTempPrev;
          CElapsedTime        m_etRequest;
          CElapsedTime        m_etRetrieve;
      };
      
      

      ElapsedTime.h

      #pragma once
      
      // used to check if set time is elapsed
      // limitation : 'isElased' method MUST be called at least 1 time every 49.71 days in order to work properly ;-)
      class CElapsedTime
      {
      public:
          // bWait1stTime means ignore timems value the very 1st call to 'isElapsed'
          CElapsedTime(uint32_t timems=0, bool bWait1stTime=false, bool bEnabled=true)
              : m_delay(timems)
              , m_bEnabled(bEnabled)
          {
              start(bWait1stTime ? timems : 0);
          };
          ~CElapsedTime() {};
      
          // start to count requested 'wait' time
          void start(uint32_t timems=0)
          {
              m_tNow = millis();
              m_tEnd = m_tNow + (timems == 0) ? m_delay : timems;
              m_bWrapped = (m_tEnd < m_tNow);
              m_bEnabled = true;
          }
      
          void disable() { m_bEnabled = false; }
      
          void setDelay(uint32_t delay) { m_delay = delay; }
      
          // check if requested time is elapsed since previous call of 'start' method
          bool isElapsed()
          {
              m_tNow = millis();
              if (m_bWrapped && (m_tNow < 0x7FFFFFFF))
              {
                  m_bWrapped = false;
              }
              return m_bEnabled && !m_bWrapped && (m_tNow > m_tEnd);
          }
      
      protected:
          uint32_t m_tNow;    // current 'time'
          uint32_t m_tEnd;    // computed end of 'time'
          uint32_t m_delay;   // used to memorize value provided in constructor
          bool m_bWrapped;    // overflow management (every around 0xFFFFFFFF/1000/3600/24 = 49.71 days)
          bool m_bEnabled;    // used to know if Elpser is enabled
      };
      
      

      RelayActuatorLrt.ino

      // History Lrt
      // 2015-12-03 v1.0 code understanding, set output pin to off at start
      // 2015-12-04 v1.1 button added
      #define WBUTTON
      // 2015-12-04 v1.2 dallas temp added
      #define WDALLASTEMP
      // 2015-12-07 v1.3 relay and button class
      // 2015-12-08 v1.4 dallas temperature device
      
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      #include <MySigningNone.h>
      #include <MyTransportNRF24.h>
      #include <MyTransportRFM69.h>
      #include <MyHwATMega328.h>
      #include <MySensor.h>
      #include <SPI.h>
      #include "Devices.h"
      
      // NRFRF24L01 radio driver (set low transmit power by default)
      MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW);
      //MyTransportRFM69 radio;
      // Message signing driver (none default)
      //MySigningNone signer;
      // Select AtMega328 hardware profile
      MyHwATMega328 hw;
      // Construct MySensors library
      MySensor gw(radio, hw);
      
      #ifndef MAP
      const int NBOFDEVICE=3;
      DECLARE_NBOFDEVICE(NBOFDEVICE+1);   // index 0 is not used
      #endif
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      void setup()
      {
        gw.begin(incomingMessage, AUTO/*, true*/);    // Initialize library and add callback for incoming messages
      
        gw.sendSketchInfo("Lrt Device R+B+T", "1.4"); // Send the sketch version information to the gateway and Controller
      
        TheSensor = &gw; // gives MySensor library to Device library
      
        CRelay(1, 3, false, true); // relay where id=1, pin=3, off at start, pesistent
      
      #ifdef WBUTTON
        CButton(2, 4, 1);          // button where id=2, pin=4 and associated relayid=1
      #endif
      
      #ifdef WDALLASTEMP
        CDallasT(3, 5, 60000);     // Dallas temp where id=3, pin=5 and period temperature retrieve is 1 min.
      //  CDallasT(4, 6, 60000);     // internal module temperature
      #endif
      }
      
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      void loop()
      {
        gw.process();     // Alway process incoming messages whenever possible
      
      #if defined WBUTTON || defined WDALLASTEMP
        // parse all devices in order to know if change occurs
      #ifdef MAP
        MapOfDevice::iterator it = g_deviceMap.begin();
        for(; it != g_deviceMap.end(); ++it)
        {
          it->second->checkChange();
        }
      #else
        for(int i=1; i<=NBOFDEVICE; i++)
        {
          g_deviceMap[i]->checkChange();
        }
      #endif
      #endif
      }
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      void incomingMessage(const MyMessage &message) {
      #ifdef DEBUG
        if (message.isAck())
        {
          Serial.print("This is an ack from GW");
        }
      #endif
        if (message.type == V_LIGHT)  // relay request from GW
        {
          g_deviceMap[message.sensor]->setState(message.getBool());
        }
      }
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      
      
      posted in Development
      lrtsenar
      lrtsenar
    • RE: Compilation problem under Arduino 1.8.1

      What the f...... hell ! I have found the problem :-). It comes from the 'static' keyword while declaring the Device derivated object in Devices.h !
      I'm happy but I don't know why this new compiler forbids this...

      See you for next adventures 😉

      posted in Troubleshooting
      lrtsenar
      lrtsenar
    • RE: Sketch Generator

      If you are interested, here is my beginning of work :

      http://forum.mysensors.org/topic/2537/device-library

      posted in Feature Requests
      lrtsenar
      lrtsenar