besonderen Dank an Jerome für seinen Sketch HM-UNI-SEN-TEMP-DS1820!
Da ich nie so genau wusste, welcher Sensor denn welche Temperatur lieferte habe ich Jeromes Sketch etwas
umgebaut:
- direkt mit der DallasTemperature Library verbunden (entsprechend muss die Library vorhanden sein!)
- auslesen der Adressen der gefundenen Sensoren (family, addr, crc) und Zuordnung zu den Indices
- Temperaturumwandlung float-> int mit Rundung
- leichte Modifikationen der Debugausgabe, nur Ausgabe wirklich vorhandenen der Temperaturen mit Rundung
Aufgrund meiner eingerosteten Programierfähigkeiten ist der entstandene Code teils merkwürdig, da ich Jeromes
Strukturen nicht vollständig verstanden habe - mein Fehler. Daher könnten einige arry-Konstrukte redundant oder
Variablen nicht im richtigen Scope sein.
Sketch läuft aber und funktioniert.
So sieht etwa der Start jetzt aus:
Code: Alles auswählen
AskSin++ V3.1.1
...
Found 3 DS1820 Sensors:
0: 10 A4.F3.98.01.08.00 B3
1: 10 EA.F7.98.01.08.00 CA
2: 10 37.30.99.01.08.00 B8
Config Changed List0
LOW BAT Limit: 22
Wake-On-Radio: 0
Sendeintervall: 180
Temperaturen: 22.6875000000 -> 227 : 22.5000000000 -> 225 : 22.6875000000 -> 227 : - : - : - : - : -
<- 16 01 84 53 F30101 00FFFF 00 41 00 E3 42 00 E1 43 00 E3 44 FB 0B - 1095
<- 16 02 84 53 F30101 00FFFF 00 45 FB 0B 46 FB 0B 47 FB 0B 48 FB 0B - 1339
Reihenfolge klar.
Ausgabezeile:
<Index>: <family> <addr_low...addr_high> <crc>
Und hier der komplette Sketch:
Code: Alles auswählen
//- -----------------------------------------------------------------------------------------------------------------------
// AskSin++
// 2016-10-31 papa 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 EI_NOTEXTERNAL
#include <EnableInterrupt.h>
#include <AskSinPP.h>
#include <LowPower.h>
#include <Register.h>
#include <MultiChannelDevice.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define MAX_SENSORS 8
// Arduino Pro mini 8 Mhz
// Arduino pin for the config button
#define CONFIG_BUTTON_PIN 8
// 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<4> LedType;
typedef AskSin<LedType, BatterySensor, RadioType> BaseHal;
DallasTemperature tsensors(&oneWire);
DeviceAddress tempDeviceAddress; // We'll use this variable to store a found device address
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_BURSTRX, 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();
burstRx(false);
lowBatLimit(22);
Sendeintervall(30);
}
};
class WeatherEventMsg : public Message {
public:
void init(uint8_t msgcnt, uint16_t* sensors, bool batlow, uint8_t channelFieldOffset) {
Message::init(0x16, msgcnt, 0x53, BCAST , batlow ? 0x80 : 0x00, 0x41 + channelFieldOffset);
pload[0] = (sensors[0 + channelFieldOffset] >> 8) & 0xff;
pload[1] = sensors[0 + channelFieldOffset] & 0xff;
pload[2] = 0x42 + channelFieldOffset;
pload[3] = (sensors[1 + channelFieldOffset] >> 8) & 0xff;
pload[4] = sensors[1 + channelFieldOffset] & 0xff;
pload[5] = 0x43 + channelFieldOffset;
pload[6] = (sensors[2 + channelFieldOffset] >> 8) & 0xff;
pload[7] = sensors[2 + channelFieldOffset] & 0xff;
pload[8] = 0x44 + channelFieldOffset;
pload[9] = (sensors[3 + channelFieldOffset] >> 8) & 0xff;
pload[10] = sensors[3 + channelFieldOffset] & 0xff;
}
};
class WeatherChannel : public Channel<Hal, List1, EmptyList, List4, PEERS_PER_CHANNEL, UList0> {
public:
WeatherChannel () : Channel() {}
virtual ~WeatherChannel () {}
void configChanged() {
//DPRINTLN("Config changed List1");
}
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;
int16_t sensors[MAX_SENSORS];
DeviceAddress tempDeviceAddress; // We'll use this variable to store a found device address
SensorArray (UType& d) : Alarm(0), dev(d) {}
virtual void trigger (__attribute__ ((unused)) AlarmClock& clock) {
tick = delay();
sysclock.add(*this);
tsensors.requestTemperatures();
DPRINT(F("Temperaturen"));
for (int i = 0; i < MAX_SENSORS; i++) {
DPRINT(": ");
sensors[i] = int(((tsensors.getTempCByIndex(i)*10)+.5));
if (sensors[i] > -126){
DDEC(tsensors.getTempCByIndex(i)); DPRINT(" -> ");
DDEC(sensors[i]); DPRINT(" ");
} else {
DPRINT("- ");
}
}
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());
_delay_ms(200);
msg.init(dev.nextcount(), sensors, dev.battery().low(), 4);
dev.send(msg, dev.getMasterID());
}
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());
DPRINT("Wake-On-Radio: ");
DDECLN(this->getList0().burstRx());
this->battery().low(this->getList0().lowBatLimit());
DPRINT("Sendeintervall: "); DDECLN(this->getList0().Sendeintervall());
}
bool init (Hal& hal) {
TSDevice::init(hal);
tsensors.begin();
sensarray.sensorcount = tsensors.getDS18Count();
DPRINT("Found "); DDEC(sensarray.sensorcount); DPRINTLN(" DS1820 Sensors:");
for (int i = 0; i < sensarray.sensorcount; i++) {
tsensors.getAddress(tempDeviceAddress,i);
DDEC(i); DPRINT(": ");
DHEX(tempDeviceAddress[0]); DPRINT(" ");
for (uint8_t ii = 1; ii < 6; ii++)
{
DHEX(tempDeviceAddress[ii]); DPRINT(".");
}
DHEX(tempDeviceAddress[6]); DPRINT(" ");
DHEX(tempDeviceAddress[7]); DPRINTLN("");
}
sensarray.set(seconds2ticks(5));
sysclock.add(sensarray);
}
};
UType sdev(devinfo, 0x20);
ConfigButton<UType> cfgBtn(sdev);
void setup () {
DINIT(57600, ASKSIN_PLUS_PLUS_IDENTIFIER);
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);
}
}
Ich grübele darüber nach, ob man das DS1820 Scratchpad mit Userbytes "füttern" sollte in einem externen "DS18020_branding" Sketch.
Dann könnte man diese 2-Byte auch zur Sortierung anstatt ds1820-serial benutzen. Dafür muss jeder Sensor einmaig "beschrieben" werden.
Auch habe ich sporadisch Aussetzer, die zeigen sich als 1* fehlerhafte Temperatur, dann ist wieder gut. DA grübele ich, ob von einem
bekannten (also schon Temperatur gesendeten) Sensor bei Temperaturfehler die "letzte gültige" Temperatur gesendet werden sollte.
sonst kann auch ein einmaliger Ausreißer zum Triggern eines Homematicscriptes führen. Da bastel ich auch noch mit Widerständen
zwischen 2k2 und 4k7, ob das was mit der Pullup auf dem onewire bei der Messung zu tun hat . Ich berichte weiter!
Viel Erfolg damit und gerne Rückmeldungen.
harvey