HM-TC-IT-WM-W-EU nachbauen
Moderator: Co-Administratoren
-
- Beiträge: 33
- Registriert: 05.12.2021, 13:48
- System: CCU
- Danksagung erhalten: 3 Mal
HM-TC-IT-WM-W-EU nachbauen
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?
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?
-
- 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
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.
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.
-
- Beiträge: 33
- Registriert: 05.12.2021, 13:48
- System: CCU
- Danksagung erhalten: 3 Mal
Re: HM-TC-IT-WM-W-EU nachbauen
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?jp112sdl hat geschrieben: ↑16.12.2021, 07:19Willst 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 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.
-
- 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
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
-
- 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
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.
Davon abgesehen wüsste ich jetzt auch nicht, wo die dazu erforderlichen Informationen zu bekommen wären.
Viele Grüße,
Hans
Hans
-
- 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
Das ist seine 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
Das ist deine Meinung:tiberius28 hat geschrieben: ↑16.12.2021, 10:05Mit dem esp8266 habe ich das schon gemacht. Das war easy. Warum sollte es hier anders sein?
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
-
- 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
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.
-
- Beiträge: 33
- Registriert: 05.12.2021, 13:48
- System: CCU
- Danksagung erhalten: 3 Mal
Re: HM-TC-IT-WM-W-EU nachbauen
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.
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.
-
- 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
Immerhin bist du da schon weiter wie ich, nur schade, dass du uns daran nicht teil haben lässt.tiberius28 hat geschrieben: ↑17.12.2021, 14:48Ich 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.
Gruß Martin
-
- Beiträge: 33
- Registriert: 05.12.2021, 13:48
- System: CCU
- Danksagung erhalten: 3 Mal
Re: HM-TC-IT-WM-W-EU nachbauen
Die Notwendigen Libraries habe ich bereits in einem anderen Thema gepostet. Nun werde ich etwas genauer.Martin62 hat geschrieben: ↑17.12.2021, 18:17Immerhin bist du da schon weiter wie ich, nur schade, dass du uns daran nicht teil haben lässt.tiberius28 hat geschrieben: ↑17.12.2021, 14:48Ich 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.
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 >> & 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 >> & 0xff) && this->writeRegister(0x22, value & 0xff);
}
uint16_t Sendeintervall () const {
return (this->readRegister(0x21, 0) << + 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 >> & 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)) << +
((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 >> & 0xff;
pload[1] = (t0) & 0xff;
pload[2] = 0x42 + channelFieldOffset;
pload[3] = (t1 >> & 0xff;
pload[4] = (t1) & 0xff;
pload[5] = 0x43 + channelFieldOffset;
pload[6] = (t2 >> & 0xff;
pload[7] = (t2) & 0xff;
pload[8] = 0x44 + channelFieldOffset;
pload[9] = (t3 >> & 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);
}
}