HM-TC-IT-WM-W-EU nachbauen

Entwicklung und Bau von Hardware aller Art, die im HM-Umfeld eingesetzt werden kann

Moderator: Co-Administratoren

Silverstar
Beiträge: 367
Registriert: 11.02.2020, 12:14
System: Alternative CCU (auf Basis OCCU)
Hat sich bedankt: 94 Mal
Danksagung erhalten: 68 Mal

Re: HM-TC-IT-WM-W-EU nachbauen

Beitrag von Silverstar » 17.12.2021, 20:45

tiberius28 hat geschrieben:
17.12.2021, 19:57
[...]

1,) HM-WDS40-TH-I-BME280_OLED

Code: Alles auswählen

//- -----------------------------------------------------------------------------------------------------------------------
// AskSin++
// 2016-10-31 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
// 2019-10-02 jp112sdl Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
//- -----------------------------------------------------------------------------------------------------------------------
// ci-test=yes board=328p aes=no

// define this to read the device id, serial and device type from bootloader section
// #define USE_OTA_BOOTLOADER

// #define USE_LCD             //bei Verwendung des LCD Displays https://www.aliexpress.com/item/1435066364.html

#define USE_OLED  1

#ifdef USE_OLED
#include <Wire.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
#define I2C_ADDRESS 0x3C

SSD1306AsciiWire oled;
#endif
//========================================================


#define EI_NOTEXTERNAL
#include <EnableInterrupt.h>
#include <AskSinPP.h>
#include <LowPower.h>

#include <MultiChannelDevice.h>
#include <sensors/Bme280.h>

#ifdef USE_LCD
#include "displays/Lcd4seg.h"
#define LCD_CS               6
#define LCD_WR               3
#define LCD_DATA             7
#define LCD_INTERVAL_SECONDS 10
#endif

// we use a Pro Mini
// Arduino pin for the LED
// D4 == PIN 4 on Pro Mini
#define LED_PIN 4
// Arduino pin for the config button
// B0 == PIN 8 on Pro Mini
#define CONFIG_BUTTON_PIN 8

//-----------------------------------------------------------------------------------------

//Korrektur von Temperatur und Luftfeuchte
//Einstellbarer OFFSET für Temperatur -> gemessene Temp +/- Offset = Angezeigte Temp.
#define OFFSETtemp 0 //z.B -50 ≙ -5°C / 50 ≙ +5°C

//Einstellbarer OFFSET für Luftfeuchte -> gemessene Luftf. +/- Offset = Angezeigte Luftf.
#define OFFSEThumi 0 //z.B -10 ≙ -10%RF / 10 ≙ +10%RF

//-----------------------------------------------------------------------------------------

// number of available peers per channel
#define PEERS_PER_CHANNEL 6

//seconds between sending messages
#define MSG_INTERVAL 180

// all library classes are placed in the namespace 'as'
using namespace as;

// define all device properties
const struct DeviceInfo PROGMEM devinfo = {
  {0x87, 0x6f, 0x99},     // Device ID
  "JPTH10I999",           // Device Serial
  {0x00, 0x3f},           // Device Model Indoor
  0x10,                   // Firmware Version
  as::DeviceType::THSensor, // Device Type
  {0x01, 0x01}            // Info Bytes
};

/**
   Configure the used hardware
*/
typedef AvrSPI<10, 11, 12, 13> SPIType;
typedef Radio<SPIType, 2> RadioType;
typedef StatusLed<LED_PIN> LedType;
typedef AskSin<LedType, BatterySensor, RadioType> Hal;
Hal hal;

#ifdef USE_LCD
  LCDToggleTH<LCD4SEG<LCD_CS, LCD_WR, LCD_DATA>> lcd;
#endif

class WeatherEventMsg : public Message {
  public:
    void init(uint8_t msgcnt, int16_t temp, uint8_t humidity, bool batlow) {
      uint8_t t1 = (temp >> 8) & 0x7f;
      uint8_t t2 = temp & 0xff;
      if ( batlow == true ) {
        t1 |= 0x80; // set bat low bit
      }
      Message::init(0xc, msgcnt, 0x70, BIDI | WKMEUP, t1, t2);
      pload[0] = humidity;
    }
};

class WeatherChannel : public Channel<Hal, List1, EmptyList, List4, PEERS_PER_CHANNEL, List0>, public Alarm {

    WeatherEventMsg msg;
    int16_t         temp;
    uint8_t         humidity;

    Bme280          bme280;
    uint16_t        millis;

  public:
    WeatherChannel () : Channel(), Alarm(5), temp(0), humidity(0), millis(0) {}
    virtual ~WeatherChannel () {}


    // here we do the measurement
    void measure () {
      DPRINT("Measure...\n");
      bme280.measure();

      temp = bme280.temperature() + OFFSETtemp;
      humidity = bme280.humidity() + OFFSEThumi;

      DPRINT("T/H = " + String(temp) + "/" + String(humidity) + "\n");
//=========================================================================
#ifdef USE_OLED
          oled.clear();
          //oled.setFont(System5x7); // Auswahl der Schriftart
          oled.println("JPTH10I999");        
          oled.println("Temp., Feucht.:");
//oled.setFont(Arial_bold_14); //4 Zeilen a 16 Zeichen
  oled.println("T = " + String(temp/10.) + " C");
  oled.println("H = "+ String(humidity) + " %"); 
#endif
//==========================================================================
     
    }

    virtual void trigger (__attribute__ ((unused)) AlarmClock& clock) {
      uint8_t msgcnt = device().nextcount();
      // reactivate for next measure
      tick = delay();
      clock.add(*this);
      measure();
#ifdef USE_LCD
      lcd.setValues(temp, humidity, device().battery().low());
#endif
      msg.init(msgcnt, temp, humidity, device().battery().low());
      if (msgcnt % 20 == 1) device().sendPeerEvent(msg, *this); else device().broadcastEvent(msg, *this);
    }

    uint32_t delay () {
      return seconds2ticks(MSG_INTERVAL);
    }
    void setup(Device<Hal, List0>* dev, uint8_t number, uint16_t addr) {
      Channel::setup(dev, number, addr);
      bme280.init();
      sysclock.add(*this);
#ifdef USE_LCD
      lcd.init();
      lcd.setToggleTime(LCD_INTERVAL_SECONDS);
#endif
    }

    uint8_t status () const {
      return 0;
    }

    uint8_t flags () const {
      return 0;
    }
};

typedef MultiChannelDevice<Hal, WeatherChannel, 1> WeatherType;
WeatherType sdev(devinfo, 0x20);
ConfigButton<WeatherType> cfgBtn(sdev);

void setup () {
  DINIT(57600, ASKSIN_PLUS_PLUS_IDENTIFIER);

#ifdef USE_OLED
  Wire.begin();
  Wire.setClock(400000L);
  oled.begin(&Adafruit128x64, I2C_ADDRESS);

  //oled.setFont(fixed_bold10x15);
  oled.setFont(Verdana12_italic);
  //oled.setFont(System5x7); // Auswahl der Schriftart
  //oled.setFont(lcdnums12x16);
  //oled.setFont(fixednums15x31);
  oled.clear(); //Löschen der aktuellen Displayanzeige
  oled.println("Viel"); //Text in der ersten Zeile. "Println" sorgt dabei für einen Zeilensprung.
  oled.println("Erfolg!!!"); // Text in der zweiten Zeile. Da es keine dritte Zeile gibt, wird hier kein Zeilenumsprung benötigt.

  delay (2000);
#endif
  
  sdev.init(hal);
  hal.initBattery(60UL * 60, 22, 19);
  buttonISR(cfgBtn, CONFIG_BUTTON_PIN);

  /* Set frequency for CC1101
 //FreqTest schreibt die Frequenz in das Eprom falls das nicht funtioniert, dann kann hier die ermittelte Frequenz eingestellt werden
 // ermittelt wurde 0x2165BA
  hal.radio.initReg(CC1101_FREQ2, 0x21);
  hal.radio.initReg(CC1101_FREQ1, 0x65);
  hal.radio.initReg(CC1101_FREQ0, 0xBA);*/
  
  sdev.initDone();
}

void loop() {
  bool worked = hal.runready();
  bool poll = sdev.pollRadio();
  if ( worked == false && poll == false ) {
    hal.activity.savePower<Sleep<>>(hal);
  }
}
2.) HB-UNI-Sen-TEMP-DS18B20-OLED

Code: Alles auswählen

//- -----------------------------------------------------------------------------------------------------------------------
// AskSin++
// 2016-10-31 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
// 2018-03-24 jp112sdl Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
//- -----------------------------------------------------------------------------------------------------------------------

// define this to read the device id, serial and device type from bootloader section
// #define USE_OTA_BOOTLOADER

#define USE_LCD  0
//#define LCD_ADDRESS 0x3f
#define LCD_ADDRESS 0x27

#define USE_OLED  1

#ifdef USE_OLED
#include <Wire.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
#define I2C_ADDRESS 0x3C

SSD1306AsciiWire oled;
#endif
//========================================================

#define EI_NOTEXTERNAL
#include <EnableInterrupt.h>
#include <AskSinPP.h>
#include <LowPower.h>

#include <Register.h>
#include <MultiChannelDevice.h>

#ifdef USE_LCD
//use this LCD lib: https://github.com/marcoschwartz/LiquidCrystal_I2C
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(LCD_ADDRESS, 20, 4);
#endif

#include <OneWire.h>
#include <sensors/Ds18b20.h>
#define MAX_SENSORS       8

// Arduino Pro mini 8 Mhz
// Arduino pin for the config button
#define CONFIG_BUTTON_PIN 8
#define LED_PIN           4

// number of available peers per channel
#define PEERS_PER_CHANNEL 6

//DS18B20 Sensors connected to pin
OneWire oneWire(3);

// all library classes are placed in the namespace 'as'
using namespace as;

// define all device properties
const struct DeviceInfo PROGMEM devinfo = {
  {0xf3, 0x01, 0x01},          // Device ID
  "UNITEMP001",               // Device Serial
  {0xF3, 0x01},              // Device Model
  0x10,                       // Firmware Version
  as::DeviceType::THSensor,   // Device Type
  {0x01, 0x01}               // Info Bytes
};

/**
   Configure the used hardware
*/
typedef AvrSPI<10, 11, 12, 13> SPIType;
typedef Radio<SPIType, 2> RadioType;
typedef StatusLed<LED_PIN> LedType;
typedef AskSin<LedType, BatterySensor, RadioType> BaseHal;
class Hal : public BaseHal {
  public:
    void init (const HMID& id) {
      BaseHal::init(id);

      battery.init(seconds2ticks(60UL * 60), sysclock); //battery measure once an hour
      battery.low(22);
      battery.critical(18);
    }

    bool runready () {
      return sysclock.runready() || BaseHal::runready();
    }
} hal;


DEFREGISTER(UReg0, MASTERID_REGS, DREG_LOWBATLIMIT, 0x21, 0x22)
class UList0 : public RegList0<UReg0> {
  public:
    UList0 (uint16_t addr) : RegList0<UReg0>(addr) {}
    bool Sendeintervall (uint16_t value) const {
      return this->writeRegister(0x21, (value >> 8) & 0xff) && this->writeRegister(0x22, value & 0xff);
    }
    uint16_t Sendeintervall () const {
      return (this->readRegister(0x21, 0) << 8) + this->readRegister(0x22, 0);
    }
    void defaults () {
      clear();
      lowBatLimit(22);
      Sendeintervall(180);
      //Sendeintervall(60);
      
    }
};

DEFREGISTER(UReg1, 0x01, 0x02, 0x03, 0x04)
class UList1 : public RegList1<UReg1> {
  public:
    UList1 (uint16_t addr) : RegList1<UReg1>(addr) {}

    bool Offset (int32_t value) const {
      return
          this->writeRegister(0x01, (value >> 24) & 0xff) &&
          this->writeRegister(0x02, (value >> 16) & 0xff) &&
          this->writeRegister(0x03, (value >> 8) & 0xff) &&
          this->writeRegister(0x04, (value) & 0xff)
          ;
    }

    int32_t Offset () const {
      return
          ((int32_t)(this->readRegister(0x01, 0)) << 24) +
          ((int32_t)(this->readRegister(0x02, 0)) << 16) +
          ((int32_t)(this->readRegister(0x03, 0)) << 8) +
          ((int32_t)(this->readRegister(0x04, 0)))
          ;
    }
    void defaults () {
      clear();
      Offset(0);
    }
};

int32_t Offsets[MAX_SENSORS];


class WeatherEventMsg : public Message {
  public:
    void init(uint8_t msgcnt, Ds18b20* sensors, bool batlow, uint8_t channelFieldOffset) {
      Message::init(0x16, msgcnt, 0x53, (msgcnt % 20 == 1) ? (BIDI | WKMEUP) : BCAST, batlow ? 0x80 : 0x00, 0x41 + channelFieldOffset);
      int16_t t0 = sensors[0 + channelFieldOffset].temperature() + Offsets[0 + channelFieldOffset];
      int16_t t1 = sensors[1 + channelFieldOffset].temperature() + Offsets[1 + channelFieldOffset];
      int16_t t2 = sensors[2 + channelFieldOffset].temperature() + Offsets[2 + channelFieldOffset];
      int16_t t3 = sensors[3 + channelFieldOffset].temperature() + Offsets[3 + channelFieldOffset];

      pload[0] = (t0 >> 8) & 0xff;
      pload[1] = (t0) & 0xff;
      pload[2] = 0x42 + channelFieldOffset;
      pload[3] = (t1 >> 8) & 0xff;
      pload[4] = (t1) & 0xff;
      pload[5] = 0x43 + channelFieldOffset;
      pload[6] = (t2 >> 8) & 0xff;
      pload[7] = (t2) & 0xff;
      pload[8] = 0x44 + channelFieldOffset;
      pload[9] = (t3 >> 8) & 0xff;
      pload[10] = (t3) & 0xff;
    }
};

class WeatherChannel : public Channel<Hal, UList1, EmptyList, List4, PEERS_PER_CHANNEL, UList0> {
  public:
    WeatherChannel () : Channel() {}
    virtual ~WeatherChannel () {}

    void configChanged() {
      //DPRINT(F("(")); DDEC(number()); DPRINTLN(F(") Config changed List1"));
      DPRINT(F("OFFSET: ")); DDECLN(this->getList1().Offset());
      Offsets[number() - 1] = this->getList1().Offset();
    }

    uint8_t status () const {
      return 0;
    }

    uint8_t flags () const {
      return 0;
    }
};

class UType : public MultiChannelDevice<Hal, WeatherChannel, MAX_SENSORS, UList0> {

    class SensorArray : public Alarm {
        UType& dev;

      public:
        uint8_t       sensorcount;
        Ds18b20       sensors[MAX_SENSORS];
        SensorArray (UType& d) : Alarm(0), dev(d), sensorcount(0) {}

        virtual void trigger (__attribute__ ((unused)) AlarmClock& clock) {
          tick = delay();
          sysclock.add(*this);

          Ds18b20::measure(sensors, sensorcount);
          DPRINT(F("Temperaturen: | "));
#ifdef USE_OLED
          oled.clear();
          oled.println("UNITEMP001");        
          oled.println("Temperaturen:");
#endif
          for (int i = 0; i < MAX_SENSORS; i++) {
            DDEC(sensors[i].temperature()); DPRINT(" | ");

#ifdef USE_OLED
             //oled.println(sensors[0].temperature());
            //uint8_t x = (i % 2 == 0 ? 0 : 10);
            //uint8_t y = i / 2;
            //lcd.setCursor(x, y);
             //oled.clear();

            String s_temp1 = " --.-";
            if ((i + 1) <= sensorcount) {
              s_temp1 = (String)((float)sensors[i].temperature() / 10.0);
              s_temp1 = s_temp1.substring(0, s_temp1.length() - 1);
              if (sensors[i].temperature() < 1000 && sensors[i].temperature() >= 0) s_temp1 = " " + s_temp1;
              //oled.println(s_temp1);
            }
            //String disp_temp1 = String(i + 1) + ":" + s_temp1 + (char)223 + "C ";
            String disp_temp1 = String(i + 1) + ":" + s_temp1 +  " C ";
            DPRINTLN(disp_temp1);
            int odd = i % 2;
            if (odd == 1) {
              oled.println(disp_temp1);
            } else {
              oled.print(disp_temp1);
            };
#endif

            
#ifdef USE_LCD
            uint8_t x = (i % 2 == 0 ? 0 : 10);
            uint8_t y = i / 2;
            lcd.setCursor(x, y);

            String s_temp = " --.-";
            if ((i + 1) <= sensorcount) {
              s_temp = (String)((float)sensors[i].temperature() / 10.0);
              s_temp = s_temp.substring(0, s_temp.length() - 1);
              if (sensors[i].temperature() < 1000 && sensors[i].temperature() >= 0) s_temp = " " + s_temp;
            }
            String disp_temp = String(i + 1) + ":" + s_temp + (char)223 + "C ";

            lcd.print(disp_temp);
#endif
          }
          DPRINTLN("");
          WeatherEventMsg& msg = (WeatherEventMsg&)dev.message();
          //Aufteilung in 2 Messages, da sonst die max. BidCos Message Size (0x1a)? überschritten wird
          msg.init(dev.nextcount(), sensors, dev.battery().low(), 0);
          dev.send(msg, dev.getMasterID());
#if MAX_SENSORS > 4
          _delay_ms(250);
          msg.init(dev.nextcount(), sensors, dev.battery().low(), 4);
          dev.send(msg, dev.getMasterID());
#endif
        }

        uint32_t delay () {
          uint16_t _txMindelay = 180;
         
          _txMindelay = dev.getList0().Sendeintervall();
          if (_txMindelay == 0) _txMindelay = 180;
          return seconds2ticks(_txMindelay);
        }

    } sensarray;

  public:
    typedef MultiChannelDevice<Hal, WeatherChannel, MAX_SENSORS, UList0> TSDevice;
    UType(const DeviceInfo& info, uint16_t addr) : TSDevice(info, addr), sensarray(*this) {}
    virtual ~UType () {}

    virtual void configChanged () {
      TSDevice::configChanged();
      DPRINTLN("Config Changed List0");
      DPRINT("LOW BAT Limit: ");
      DDECLN(this->getList0().lowBatLimit());
      this->battery().low(this->getList0().lowBatLimit());
      DPRINT("Sendeintervall: "); DDECLN(this->getList0().Sendeintervall());
    }

    void init (Hal& hal) {
      TSDevice::init(hal);
      sensarray.sensorcount = Ds18b20::init(oneWire, sensarray.sensors, MAX_SENSORS);
      DPRINT("Found "); DDEC(sensarray.sensorcount); DPRINTLN(" DS18B20 Sensors");
#ifdef USE_LCD
      lcd.setCursor(2, 3);
      lcd.print("Found Sensors: " + String(sensarray.sensorcount));
#endif
      sensarray.set(seconds2ticks(5));
      sysclock.add(sensarray);
    }
};

UType sdev(devinfo, 0x20);
ConfigButton<UType> cfgBtn(sdev);

void setup () {
  DINIT(57600, ASKSIN_PLUS_PLUS_IDENTIFIER);
  memset(Offsets, 0, MAX_SENSORS);
  DDEVINFO(sdev);

#ifdef USE_LCD
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("UNI-Sen-TEMP-DS18B20");
  lcd.setCursor(5, 1);
  lcd.print((char*)serial);
  HMID temp;
  sdev.getDeviceID(temp);
  lcd.setCursor(7, 2);
  lcd.print(temp, HEX);
#endif

#ifdef USE_OLED
  Wire.begin();
  Wire.setClock(400000L);
  oled.begin(&Adafruit128x64, I2C_ADDRESS);

  oled.setFont(System5x7); // Auswahl der Schriftart
  oled.clear(); //Löschen der aktuellen Displayanzeige
  oled.println("Viel"); //Text in der ersten Zeile. "Println" sorgt dabei für einen Zeilensprung.
  oled.println("Erfolg!!!"); // Text in der zweiten Zeile. Da es keine dritte Zeile gibt, wird hier kein Zeilenumsprung benötigt.
  delay (2000);
#endif



  sdev.init(hal);
  buttonISR(cfgBtn, CONFIG_BUTTON_PIN);
  sdev.initDone();
}

void loop() {

   bool worked = hal.runready();
   bool poll = sdev.pollRadio();
   if ( worked == false && poll == false ) {
    if ( hal.battery.critical() ) {
      hal.activity.sleepForever(hal);
    }
    hal.activity.savePower<Sleep<>>(hal);
  }
}
Bitte in

Code: Alles auswählen

[code][ /code]
tags posten.

Ansonsten, Danke, dass du deine Arbeit mit uns teilst!

Antworten

Zurück zu „Hardwareentwicklung und Selbstbau von Aktoren und Sensoren“