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

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

Moderator: Co-Administratoren

tiberius28
Beiträge: 33
Registriert: 05.12.2021, 13:48
System: CCU
Danksagung erhalten: 3 Mal

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

Beitrag von tiberius28 » 16.12.2021, 06:17

Habe einen Temperatur und Feuchtigkeitssensor mit Displayanzeige (für Raumklimaüberwachung) (nach)gebaut. Nun möchte ich diesen zum Wandthermostaten erweitern und die Funktionen des HM-TC-IT-WM-W-EU nachbilden. Dabei denke ich daran, eine Möglichkeit zu schaffen eine Solltemperatur einzustellen. Dafür müsste ich folgendes tun:
1. Hinzufügen von zwei Tastern (einer für Plus +, einer für Minus)
2. Einstellen einer Initialtemperatur (z.B. 12 Grad),
3. Einstellen eines Schrittwertes (0,5 Grad),
4. Drücken der Plus-Taste hebt die Solltemperatur um den Schrittwert an, Minus senkt die Solltemperatur ab
5. Der eingestellte Wert der Solltemperatur an die Zentrale melden, damit diese von anderen Geräten abgerufen werden kann.

Bin sehr dankbar für Tipps und Hinweise, wie ich diese Erweiterung umsetzen kann.
Ich bin sehr begeistert von der asksinpp-Library. Ich würde gerne mehr Hintergrundwissen aneignen. Ich besitze C++-Grundkenntnisse und Klassen und Methoden sagen mir schon etwas, habe aber noch nie, selbst welche konzipiert und implementiert. Damit im Zusammenhang habe ich folgende Fragen:
a.) Gibt es ein asksinpp-Tutorial in dem Näheres zu den Funktionen erklärt wird?
b.) Da ich schon einige Geräte nachgebaut habe, würde ich gerne mehr erfahren, was im Hintergrund gerade abläuft. Dafür wäre ein Debug-Modus sehr hilfreich, der z.B. im Serial Monitor anzeigt, welche Methode gerade zur Anwendung kommt und welches die Ein- und Ausgabewerte sind. Gibt es einen Debugmodus? Wie wird dieser eingestellt?
c.) Gerne würde ich meine Erkenntnisse und Erfahrungen dokumentieren und dem Forum zur Verfügung zu stellen. Die Dokumentation würde sich insbesondere an die Programmierlaien richten und sollte eine methodische Unterstützung sein, wie man mit Programmiergrundkenntnisse Geräte erweitern kann. Z.B. könnte ich mir "Trampelpfade" vorstellen wie:
I.) Wie füge ich einen Schalter, Taster hinzu?
II.) Wie füge ich eine LED-hinzu, die einen Schaltzustand anzeigt?
III.) Wie stelle ich ein, dass ein Wert, Schaltzustand and die Zentrale gesendet wird?

jp112sdl
Beiträge: 12116
Registriert: 20.11.2016, 20:01
Hat sich bedankt: 849 Mal
Danksagung erhalten: 2150 Mal
Kontaktdaten:

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

Beitrag von jp112sdl » 16.12.2021, 07:19

Willst du denn ein Gerät bauen, das genau dem "HM-TC-IT-WM-W-EU" entspricht?
Das ist ein ganz schöner Brocken, wenn ich mir die zig Register anschaue für die ganzen Wochenprofile.
Auch wenn du die nicht benötigst, musst du sie trotzdem implementieren, damit die CCU ihren kompletten Paramset ans Gerät loswird und auch jeden einzelnen Parameterwert bestätigt bekommt.

Oder will du ein neues "custom" Gerät bauen? Würde sich ja anbieten, wenn du nur ein paar wenige Funktionen benötigst.
Dann musst du dich neben der AskSin++ Geschichte auch noch in die Thematik "Bereitstellung benutzerdefinierter Geräte in der CCU" einarbeiten.

VG,
Jérôme ☕️

---
Support for my Homebrew-Devices: Download JP-HB-Devices Addon

tiberius28
Beiträge: 33
Registriert: 05.12.2021, 13:48
System: CCU
Danksagung erhalten: 3 Mal

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

Beitrag von tiberius28 » 16.12.2021, 10:05

jp112sdl hat geschrieben:
16.12.2021, 07:19
Willst du denn ein Gerät bauen, das genau dem "HM-TC-IT-WM-W-EU" entspricht?
Das ist ein ganz schöner Brocken, wenn ich mir die zig Register anschaue für die ganzen Wochenprofile.
Auch wenn du die nicht benötigst, musst du sie trotzdem implementieren, damit die CCU ihren kompletten Paramset ans Gerät loswird und auch jeden einzelnen Parameterwert bestätigt bekommt.

Oder will du ein neues "custom" Gerät bauen? Würde sich ja anbieten, wenn du nur ein paar wenige Funktionen benötigst.
Dann musst du dich neben der AskSin++ Geschichte auch noch in die Thematik "Bereitstellung benutzerdefinierter Geräte in der CCU" einarbeiten.
Ich möchte eigentlich nur die Punkte 1-5 dem Temperatursensor hinzufügen. Also Custom mehr nicht. Es dürfte keine große Sache sein, wenn man etwas Hintergrundwissen hat. Mit dem esp8266 habe ich das schon gemacht. Das war easy. Warum sollte es hier anders sein?
Ich würde mich gerne in die o.g. Thematik einarbeiten. Das einzige Material das ich bisher gefunden und durchgearbeitet habe, sind die Grundlagen (https://asksinpp.de/Grundlagen/). Darüber hinaus konnte ich nichts finden. Bin dankbar für jeden Hinweis.

Martin62
Beiträge: 681
Registriert: 09.12.2019, 21:24
Hat sich bedankt: 151 Mal
Danksagung erhalten: 61 Mal

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

Beitrag von Martin62 » 16.12.2021, 11:37

Das ist an der Stelle nicht so einfach, da es eine Beschreibung in diesem Sinne nicht gibt. Das musst du dir hier im Forum und im Netz zusammen suchen. Ich Versuche auch schon einige Zeit da einen Fuß reinzubekommen. Am besten über die Projekte und Sketche auf der Asksinpp.de Seite sich mal durcharbeiten.
Gruß Martin

rih
Beiträge: 123
Registriert: 09.05.2019, 23:04
System: keine Zentrale (nur Pairing, FHEM etc.)
Wohnort: Nürtingen
Hat sich bedankt: 19 Mal
Danksagung erhalten: 10 Mal

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

Beitrag von rih » 16.12.2021, 17:31

Ich bastle ja auch gern und habe schon einige Homematik-Geräte nach- und umgebaut. Aber in diesem speziellen Fall (HM-TC-IT-WM-W-EU) würde ich dringend empfehlen den ELV-Bausatz zu kaufen. Kostet 34,95 Euro versandkostenfrei. Damit stehen Dir alle sehr umfangreichen Features des Gerätes zur weiteren Verwendung zur Verfügung und Du hast keine Probleme mit dem Einbinden in die CCU. Bei einem Selbstbau müsstest Du, wie Jerome schon schrieb, außer der AskSinPP-Software auch noch die Software für die Erkennung des Selbstbau-Gerätes in der CCU (Addon) schreiben. Das alles ist weder trivial noch den Aufwand in diesem Fall wert. Meine Meinung.
Davon abgesehen wüsste ich jetzt auch nicht, wo die dazu erforderlichen Informationen zu bekommen wären.
Viele Grüße,
Hans

jp112sdl
Beiträge: 12116
Registriert: 20.11.2016, 20:01
Hat sich bedankt: 849 Mal
Danksagung erhalten: 2150 Mal
Kontaktdaten:

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

Beitrag von jp112sdl » 16.12.2021, 21:41

Das ist seine Meinung:
tiberius28 hat geschrieben:
16.12.2021, 10:05
Mit dem esp8266 habe ich das schon gemacht. Das war easy. Warum sollte es hier anders sein?
Das ist deine Meinung:
rih hat geschrieben:
16.12.2021, 17:31
außer der AskSinPP-Software auch noch die Software für die Erkennung des Selbstbau-Gerätes in der CCU (Addon) schreiben. Das alles ist weder trivial noch den Aufwand in diesem Fall wert. Meine Meinung.
Das ist meine Meinung:
Ich könnte mir schon vorstellen, zumindest zu erklären, was man auf der CCU-Seite machen muss, um einen eigenen Gerätetyp dort nutzen zu können. Aber bevor ich hier mit langen Erklärungen anfange, schaue ich erstmal nach dem Verhältnis von Geben und Nehmen viewtopic.php?f=76&t=71321&p=694034#p694034

Ich hab über ein halbes Jahr benötigt, um die Zusammenhänge - sei es Funktionen innerhalb der Sketche als auch auf der CCU - zu verstehen.
ESPeasy ist in 2min. geflasht.
Ich frag mich, was da anders ist 8)

VG,
Jérôme ☕️

---
Support for my Homebrew-Devices: Download JP-HB-Devices Addon

der-pw
Beiträge: 435
Registriert: 26.01.2019, 13:39
Wohnort: Wolfenbüttel
Hat sich bedankt: 126 Mal
Danksagung erhalten: 100 Mal
Kontaktdaten:

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

Beitrag von der-pw » 17.12.2021, 11:51

jp112sdl hat geschrieben:
16.12.2021, 21:41
Aber bevor ich hier mit langen Erklärungen anfange, schaue ich erstmal nach dem Verhältnis von Geben und Nehmen viewtopic.php?f=76&t=71321&p=694034#p694034
Sehr treffend, Jérôme!


Ich möchte nochmal anfügen, dass es neben evtl. "Geiz" wohl auch den Faktor "Scham" gibt.
Scham darüber, sich nicht zu trauen, seine Projekte und Änderungen hier zu zeigen, weil der Code nicht Schick genug ist.
Wenn das der Fall ist, kann ich nur sagen, dass es mich anfangs auch etwas Überwindung gekostet hat, meinen "Quark" hier zu zeigen, aber eigentlich habe ich immer was mitgenommen aus den Tipps die ich sonst nicht erhalten hätte, wenn ich nur für mich rumgewerkelt hätte.
Und gerade Jérôme (und natürlich auch viele andere aktive Mtglieder hier) ist/sind sehr hilfsbereit, wenn auch am Ende was zurück kommt.
Das nur mal als meine bescheidene OT-Meinung. ;-)
Grüße,
Patrick

https://github.com/der-pw

tiberius28
Beiträge: 33
Registriert: 05.12.2021, 13:48
System: CCU
Danksagung erhalten: 3 Mal

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

Beitrag von tiberius28 » 17.12.2021, 14:48

Ich habe mir diese Erweiterung als Aufgabe gestellt, nicht um Geld zu sparen, sondern um den Zusammenhängen dahinter zu steigen, um dieses System kennenzulernen, das mich in der Lage versetzt, kleinere Anpassungen zu machen. Mein Vorgehen bisher:

Ich habe die Sensoren gebaut HB-UNI-Sen-TEMP-DS18B20 und HM-WDS40-TH-I-BME280. Ich habe es geschafft diese mit einem Oled SSD1306 "nachzurüsten". Das war für mich ein erster Erfolg.

Als nächstes habe ich mir vorgenommen, noch eine Display-Button hinzuzufügen, um einige Funktionen wie Z.B.:
- Anzeige löschen oder
- Nächste Temperatur anzeigen.
Mir kommt das eigentlich trivial vor. Habe viel Zeit schon damit verbracht, diesmal leider ohne Erfolg.
Das Forum ist nun meine letzte Hoffnung. Erhalte ich hier keine Hinweise, dann werde ich es wohl aufgeben müssen. Das ist schade.

Martin62
Beiträge: 681
Registriert: 09.12.2019, 21:24
Hat sich bedankt: 151 Mal
Danksagung erhalten: 61 Mal

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

Beitrag von Martin62 » 17.12.2021, 18:17

tiberius28 hat geschrieben:
17.12.2021, 14:48
Ich habe die Sensoren gebaut HB-UNI-Sen-TEMP-DS18B20 und HM-WDS40-TH-I-BME280. Ich habe es geschafft diese mit einem Oled SSD1306 "nachzurüsten". Das war für mich ein erster Erfolg.
Immerhin bist du da schon weiter wie ich, nur schade, dass du uns daran nicht teil haben lässt.
Gruß Martin

tiberius28
Beiträge: 33
Registriert: 05.12.2021, 13:48
System: CCU
Danksagung erhalten: 3 Mal

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

Beitrag von tiberius28 » 17.12.2021, 19:57

Martin62 hat geschrieben:
17.12.2021, 18:17
tiberius28 hat geschrieben:
17.12.2021, 14:48
Ich habe die Sensoren gebaut HB-UNI-Sen-TEMP-DS18B20 und HM-WDS40-TH-I-BME280. Ich habe es geschafft diese mit einem Oled SSD1306 "nachzurüsten". Das war für mich ein erster Erfolg.
Immerhin bist du da schon weiter wie ich, nur schade, dass du uns daran nicht teil haben lässt.
Die Notwendigen Libraries habe ich bereits in einem anderen Thema gepostet. Nun werde ich etwas genauer.

Temperaturausgaben auf Oled SSD1306 an I2C angeschlossen.

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

//- -----------------------------------------------------------------------------------------------------------------------
// 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

//- -----------------------------------------------------------------------------------------------------------------------
// 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.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.temperature() / 10.0);
s_temp1 = s_temp1.substring(0, s_temp1.length() - 1);
if (sensors.temperature() < 1000 && sensors.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.temperature() / 10.0);
s_temp = s_temp.substring(0, s_temp.length() - 1);
if (sensors.temperature() < 1000 && sensors.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);
}
}

Antworten

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