Hallo zusammen,
Ich habe mir diesen Sensor nachgebaut.
https://github.com/TomMajor/SmartHome/tree/master/HB-Sec-WDS-2 (https://github.com/TomMajor/SmartHome/tree/master/HB-Sec-WDS-2)
Erstmal danke für das tolle Projekt.
Der Sensor funktioniert in der Standard Variante einwandfrei, FHEM erkennt ihn als HM-Sec-WDS-2.
Es gibt allerdings noch eine "CUSTOM" Variante als Sketch, in diesem wird die Batteriespannung mit übertragen. Dieses Feature würde ich gerne nutzen, allerdings lässt sich der Sensor als "CUSTOM" nicht an FHEM anlernen.
Das liegt, wie ich mittlerweile herausgefunden habe daran, das es für FHEM ein unbekanntes Gerät ist.
Um die AskSin++ Nachbauten an FHEM anzulernen muss ja auch das FHEM Homebrew Addon https://github.com/pa-pa/AskSinPP/tree/master/examples/custom/contrib/FHEM (https://github.com/pa-pa/AskSinPP/tree/master/examples/custom/contrib/FHEM) installiert sein, jedoch ist hier der HB-Sec-WDS-2 nicht vorhanden.
Ich habe dann mal probiert, diesen hinzuzufügen.
Das sieht wie folgt aus.
# water contact WDS3
$HMConfig::culHmModel{"F121"} = {name=>"HB-Sec-WDS-3",st=>'custom',cyc=>'28:00',rxt=>'c:w:l',lst=>'1,4:1p',chn=>""};
$HMConfig::culHmChanSets{"HB-Sec-WDS-3"} = $HMConfig::culHmSubTypeSets{"THSensor"};
$HMConfig::culHmRegModel{"HB-Sec-WDS-3"} = { lowBatLimitBA2=>1, transmDevTryMax=>1, cyclicInfoMsg=>1,
msgWdsPosA=>1, msgWdsPosB=>1, msgWdsPosC=>1, eventFilterTimeB=>1 };
$customMsg{"HB-Sec-RHS-3"} = sub {
my ($msg,$target) = @_;
my $batflags = 0;
my $bat = 0;
my $device = main::CUL_HM_id2Hash($msg->from);
my @evtEt = $msg->processThreeState($target,(0=>'dry',100=>'water',200=>'wet')) if $msg->channel == 1;
if( $msg->isSensor ) {
# add battery value
$bat = $msg->payloadByte(3);
$batflags = $msg->payloadByte(0);
}
if( $msg->isStatus ) {
# add battery value
$bat = $msg->payloadByte(5);
$batflags = $msg->payloadByte(3);
}
# add battery state
my $batstat = "ok";
$batstat = "low" if (($batflags & 0x80)==0x80);
push @evtEt,[$device,1,"battery:".$batstat];
push @evtEt,[$device,1,"batVoltage:".$bat/10];
return @evtEt;
};
Das hat aber leider nicht zu dem gewünschten Erfolg geführt.
Kann mir jemand auf die Sprünge helfen oder mir einen Tip geben, wo ich mich einlesen kann?
Ich möchte lediglich die Batteriespannung in Vilt noch angezeigt bekommen.
Danke im Voraus!
Hier
$customMsg{"HB-Sec-RHS-3"} = sub {
muss auf jeden Fall schon mal
$customMsg{"HB-Sec-WDS-3"} = sub {
stehen. Den Rest habe ich jetzt noch nicht im Detail angesehen.
Zitat von: papa am 19 Januar 2021, 19:58:15
Hier
$customMsg{"HB-Sec-RHS-3"} = sub {
muss auf jeden Fall schon mal
$customMsg{"HB-Sec-WDS-3"} = sub {
stehen. Den Rest habe ich jetzt noch nicht im Detail angesehen.
Danke!
Einen Schritt weiter, er lässt sich anlernen und wird als WDS-3 erkannt.
Allerdings kommen nucht alle Readings durch, ein list sieht so aus:
Internals:
CFGFN
DEF B5B102
FUUID 60072e88-f33f-000f-cbbc-cc5943e4a71e206a
HMLAN1_MSGCNT 21
HMLAN1_RAWMSG EB5B102,0000,9DBD305F,FF,FFB2,028000B5B102169E8E13F121574154455243484B303080010100
HMLAN1_RSSI -78
HMLAN1_TIME 2021-01-19 20:13:40
IODev HMLAN1
LASTInputDev Maple3_868
MSGCNT 84
Maple1_868_MSGCNT 21
Maple1_868_RAWMSG A1A028000B5B102169E8E13F121574154455243484B303080010100::-70.5:Maple1_868
Maple1_868_RSSI -70.5
Maple1_868_TIME 2021-01-19 20:13:40
Maple2_433_MSGCNT 21
Maple2_433_RAWMSG A1A028000B5B102169E8E13F121574154455243484B303080010100::-82:Maple2_433
Maple2_433_RSSI -82
Maple2_433_TIME 2021-01-19 20:13:40
Maple3_868_MSGCNT 21
Maple3_868_RAWMSG A1A028000B5B102169E8E13F121574154455243484B303080010100::-75.5:Maple3_868
Maple3_868_RSSI -75.5
Maple3_868_TIME 2021-01-19 20:13:41
NAME HM_B5B102
NOTIFYDEV global
NR 47967
STATE ???
TYPE CUL_HM
chanNo 01
lastMsg No:02 - t:00 s:B5B102 d:169E8E 13F121574154455243484B303080010100
protLastRcv 2021-01-19 20:13:40
protRcv 7 last_at:2021-01-19 20:13:40
protSnd 18 last_at:2021-01-19 20:12:48
protState CMDs_done
rssi_at_HMLAN1 cnt:22 min:-85 max:-73 avg:-79.36 lst:-78
rssi_at_Maple1_868 cnt:21 min:-76.5 max:-63.5 avg:-68.04 lst:-70.5
rssi_at_Maple2_433 cnt:21 min:-96 max:-69.5 avg:-81.14 lst:-82
rssi_at_Maple3_868 cnt:21 min:-78 max:-63.5 avg:-68.85 lst:-75.5
READINGS:
2021-01-19 20:13:40 D-firmware 1.3
2021-01-19 20:13:40 D-serialNr WATERCHK00
2021-01-19 20:12:48 commState CMDs_done
2021-01-19 20:12:45 trigger_cnt 0
helper:
HM_CMDNR 41
PONtest 1
mId 0000
peerFriend
peerOpt -:-
regLst
rxType 1
supp_Pair_Rep 1
cmds:
TmplKey :no:1611083405.59055
TmplTs 1611083405.59055
cmdKey 1:1:1::HM_B5B102:0000:01:
cmdLst:
clear (readings|all)
peerChan -btnNumber- -actChn- [({single}|dual|reverse)] [({set}|unset)] [(actor|remote|{both})]
postEvent -condition-
press [(long|{short})] [(-peer-|{all})] [(noBurst|{Burst})] [(-repCount-|{0})] [(-repDelay-|{0.25})]
pressL [(-peer-|{all})]
pressS [(-peer-|{all})]
update noArg
virtual [(1..50;1|{1})]
lst:
condition slider,0,1,255
peer
peerOpt
tplDel
rtrvLst:
cmdList [({short}|long)]
listDevice [({all}|alive|unknown|dead|notAlive)]
param -param-
status noArg
expert:
def 1
det 0
raw 0
tpl 0
io:
nextSend 1611083621.09788
prefIO
vccu
mRssi:
mNo 02
io:
HMLAN1:
-76
-76
Maple1_868:
-70.5
-70.5
Maple2_433:
-82
-82
Maple3_868:
-75.5
-75.5
prt:
bErr 0
sProc 0
rspWait:
q:
qReqConf
qReqStat
role:
chn 1
dev 1
vrt 1
rssi:
at_HMLAN1:
avg -79.3636363636364
cnt 22
lst -78
max -73
min -85
at_Maple1_868:
avg -68.047619047619
cnt 21
lst -70.5
max -63.5
min -76.5
at_Maple2_433:
avg -81.1428571428572
cnt 21
lst -82
max -69.5
min -96
at_Maple3_868:
avg -68.8571428571428
cnt 21
lst -75.5
max -63.5
min -78
tmpl:
Attributes:
IODev HMLAN1
alias HM_B5B102
firmware 1.3
model HB-Sec-WDS-3
peerIDs ,
room CUL_HM
serialNr WATERCHK00
subType virtual
subType virtual
Das ist auf jeden Fall falsch. Am besten das Device nochmal löschen. FHEM neu starten und dann nochmal anlernen.
Es war wohl der FHEM Neustart, habe bisher imme rnur ein reload der Datei gemacht.
Update:
Sensor wir jetzt sauber gepaired und überträgt alle gewünschten Readings, der State funktioniert auch sauber.
READINGS:
2021-01-20 07:26:26 D-firmware 1.3
2021-01-20 07:26:26 D-serialNr WATERCHK00
2021-01-20 07:26:26 PairedTo 0x169E9F
2021-01-20 07:26:26 RegL_00. 00:00 09:01 0A:16 0B:9E 0C:8E 12:18 14:06
2021-01-20 07:26:27 RegL_01. 00:00 08:00 20:78 23:05 30:06
2021-01-20 07:40:35 batVoltage 1
2021-01-20 07:40:35 battery ok
2021-01-20 07:26:26 cfgState updating
2021-01-20 07:40:36 commState CMDs_done
2021-01-20 07:40:35 contact dry (to VCCU)
2021-01-20 07:40:35 state dry
2021-01-20 07:40:35 trigger_cnt 5
Attributes:
IODev HMLAN1
alias HM_A5B102
autoReadReg 4_reqStatus
expert rawReg
firmware 1.3
model HB-Sec-WDS-3
peerIDs 00000000,
room CUL_HM
serialNr WATERCHK00
subType custom
Das einzige Manko ist jetzt noch, das die batVoltage immer bei 1 bleibt, obwohl auf der seriellen Konsole der richtige Wert angezeigt wird.
Denke das wird das falsche payload bit sein, welches ich gewählt habe. (HAbe das ja nur aus dem Beispiel von papa´s RHS3 übernommen, das kann ja eigentlicht nicht passen)
An welcher Stelle im Sketch wird dieses bit festgelegt?
//---------------------------------------------------------
// HB-Sec-WDS-2
// Version 1.07
// (C) 2018-2021 Tom Major (Creative Commons)
// https://creativecommons.org/licenses/by-nc-sa/4.0/
// You are free to Share & Adapt under the following terms:
// Give Credit, NonCommercial, ShareAlike
// +++
// AskSin++ 2016-10-31 papa Creative Commons
//---------------------------------------------------------
// clang-format off
//---------------------------------------------------------
// User definitions
// General
#define WDS2_CUSTOM // mögliche Geräte: WDS2_STANDARD / WDS2_CUSTOM
#define THREE_STATE // TWO_STATE: nur Status Trocken/Wasser (4 Elektroden), THREE_STATE: Status Trocken/Feucht/Wasser (5 Elektroden)
#define MEASUREMENT_INTERVAL 60 // jede Minute messen
// Pins
#define CONFIG_BUTTON_PIN 3
#define LED_PIN1 4
#define LED_PIN2 5
#define SENS_PIN_WET A3 // ADC sensor pin (TWO_STATE: Wasser / THREE_STATE: Feucht)
#define SENS_PIN_WATER A2 // ADC sensor pin (TWO_STATE: nicht benutzt / THREE_STATE: Wasser)
// Parameters
#define BAT_VOLT_LOW 24 // 2.4V
#define BAT_VOLT_CRITICAL 22 // 2.2V
#define DETECTION_THRESHOLD 800 // Wasser-Erkennung, Vergleichswert ADC
#define PEERS_PER_CHANNEL 6 // number of available peers per channel
//---------------------------------------------------------
// clang-format on
//---------------------------------------------------------
// Schaltungsvariante und Pins für Batteriespannungsmessung, siehe README HB-UNI-Sensor1
// Standard: tmBattery, UBatt = Betriebsspannung AVR
//#define BAT_SENSOR tmBattery
// Echte Batteriespannungsmessung unter Last, siehe HB-UNI-Sensor1 und Thema "Babbling Idiot Protection"
// tmBatteryLoad: sense pin A0, activation pin D6, Faktor = Rges/Rlow*1000, z.B. 10/30 Ohm, Faktor 40/10*1000 = 4000, 200ms Belastung vor Messung
#define BAT_SENSOR tmBatteryLoad<A0, 6, 4000, 200>
//---------------------------------------------------------
// NDEBUG sollte aktiviert werden wenn die Entwicklung und die Tests abgeschlossen sind und das Gerät in den 'Produktionsmodus' geht.
//#define NDEBUG
//---------------------------------------------------------
// 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 <ContactState.h>
#include "tmBattery.h"
// all library classes are placed in the namespace 'as'
using namespace as;
// define all device properties
const struct DeviceInfo PROGMEM devinfo = {
{ 0xA5, 0xB1, 0x02 }, // Device ID
"WATERCHK00", // Device Serial
#ifdef WDS2_STANDARD
{ 0x00, 0xb2 }, // Device Model Standard HM-SEC-WDS-2
#elif defined WDS2_CUSTOM
{ 0xF1, 0x21 }, // Device Model Custom HB-SEC-WDS-2
#else
#error "Invalid device define"
#endif
0x13, // Firmware Version
as::DeviceType::ThreeStateSensor, // Device Type
{ 0x01, 0x00 } // Info Bytes
};
// --------------------------------------------------------
// Configure the used hardware
typedef AvrSPI<10, 11, 12, 13> SPIType;
typedef Radio<SPIType, 2> RadioType;
typedef DualStatusLed<LED_PIN1, LED_PIN2> LedType;
typedef AskSin<LedType, BAT_SENSOR, RadioType> HalType;
class WdsHal : public HalType {
public:
#ifdef WDS2_CUSTOM
void prepareSend(Message& msg)
{
if (msg.isSensorEvent() || msg.isInfoActuatorStatusMsg()) {
uint16_t batteryVoltage = battery.current(); // BatteryTM class, mV resolution
msg.append(batteryVoltage);
}
}
#endif
};
DEFREGISTER(Reg0, MASTERID_REGS, DREG_CYCLICINFOMSG, DREG_LOWBATLIMIT, DREG_TRANSMITTRYMAX)
class WDSList0 : public RegList0<Reg0> {
public:
WDSList0(uint16_t addr)
: RegList0<Reg0>(addr)
{
}
void defaults()
{
clear();
cycleInfoMsg(true);
lowBatLimit(BAT_VOLT_LOW);
transmitDevTryMax(6);
}
};
DEFREGISTER(Reg1, CREG_AES_ACTIVE, CREG_MSGFORPOS, CREG_EVENTFILTERTIME, CREG_TRANSMITTRYMAX)
class WDSList1 : public RegList1<Reg1> {
public:
WDSList1(uint16_t addr)
: RegList1<Reg1>(addr)
{
}
void defaults()
{
clear();
msgForPosA(1); // DRY
msgForPosB(3); // WET
msgForPosC(2); // WATER
aesActive(false);
eventFilterTime(5);
transmitTryMax(6);
}
};
//---------------------------------------------------------
// Wassermelder ADC/Position extension
//
// Sensor pin Masse: 4.7k nach Masse
// Sensor pin Wet: 4.7k zum ADC Eingang SENS_PIN_WET (A3), 100k vom ADC Eingang nach +3V
// Sensor pin Water: 4.7k zum ADC Eingang SENS_PIN_WATER (A2), 100k vom ADC Eingang nach +3V
//
// ADC Werte mit 10mm Abstand zwischen den Sensorpins, Batteriespannung 3V:
// offen 1023
// gebrückt 88
// Wasser 550-650
// Mineralwasser ca. 550
// Sekt ca. 500
//---------------------------------------------------------
class ADCPosition : public Position {
uint8_t m_SensePinWet, m_SensePinWater;
public:
ADCPosition()
: m_SensePinWet(0)
, m_SensePinWater(0)
{
_present = true;
}
void init(uint8_t adcPinWet, uint8_t adcPinWater)
{
m_SensePinWet = adcPinWet;
m_SensePinWater = adcPinWater;
pinMode(m_SensePinWet, INPUT);
digitalWrite(m_SensePinWet, LOW); // kein pull-up
pinMode(m_SensePinWater, INPUT);
digitalWrite(m_SensePinWater, LOW); // kein pull-up
}
void measure(__attribute__((unused)) bool async = false)
{
// after device reset, make sure to always trigger a first message if not in dry state
static bool onlyOnce = false;
if (!onlyOnce) {
onlyOnce = true;
_position = State::PosA;
DPRINTLN(F("Init Pos"));
return;
}
uint16_t adcWet = measureChannel(m_SensePinWet);
DPRINT(F("ADC Wet: "));
DDECLN(adcWet);
#ifdef THREE_STATE
uint16_t adcWater = measureChannel(m_SensePinWater);
DPRINT(F("ADC Water: "));
DDECLN(adcWater);
#endif
#ifdef TWO_STATE
// SENS_PIN_WATER wird nicht benutzt
if (adcWet < DETECTION_THRESHOLD) {
_position = State::PosC;
DPRINTLN(F("Status: WATER"));
} else {
_position = State::PosA;
DPRINTLN(F("Status: DRY"));
}
#elif defined THREE_STATE
if (adcWater < DETECTION_THRESHOLD) {
_position = State::PosC;
DPRINTLN(F("Status: WATER"));
} else if (adcWet < DETECTION_THRESHOLD) {
_position = State::PosB;
DPRINTLN(F("Status: WET"));
} else {
_position = State::PosA;
DPRINTLN(F("Status: DRY"));
}
#else
#error "Invalid state define"
#endif
}
uint16_t measureChannel(uint8_t pin)
{
// setup ADC: complete ADC init in case other modules have chamged this
ADCSRA = 1 << ADEN | 1 << ADPS2 | 1 << ADPS1 | 1 << ADPS0; // enable ADC, prescaler 128 = 62.5kHz ADC clock @8MHz (range 50..1000 kHz)
ADMUX = 1 << REFS0; // AREF: AVCC with external capacitor at AREF pin
ADCSRB = 0;
uint8_t channel = pin - PIN_A0;
ADMUX |= (channel & 0x0F); // select channel
delay(30); // load CVref 100nF, 5*Tau = 25ms
// 1x dummy read, dann Mittelwert aus 4 samples
uint16_t adc = 0;
for (uint8_t i = 0; i < 5; i++) {
ADCSRA |= 1 << ADSC;
uint8_t timeout = 50; // start ADC
while (ADCSRA & (1 << ADSC)) {
delayMicroseconds(10);
timeout--;
if (timeout == 0)
break;
}
if (i > 0) {
adc += (ADC & 0x3FF);
}
}
return (adc >> 2);
}
uint32_t interval() { return seconds2ticks(MEASUREMENT_INTERVAL); }
};
// --------------------------------------------------------
template <class HALTYPE, class List0Type, class List1Type, class List4Type, int PEERCOUNT>
class ADCThreeStateChannel : public StateGenericChannel<ADCPosition, HALTYPE, List0Type, List1Type, List4Type, PEERCOUNT> {
public:
typedef StateGenericChannel<ADCPosition, HALTYPE, List0Type, List1Type, List4Type, PEERCOUNT> BaseChannel;
ADCThreeStateChannel()
: BaseChannel() {};
~ADCThreeStateChannel() {}
void init(uint8_t adcpin1, uint8_t adcpin2)
{
BaseChannel::init();
BaseChannel::possens.init(adcpin1, adcpin2);
#ifdef WDS2_STANDARD
DPRINTLN(F("Device: WDS2_STANDARD"));
#elif defined WDS2_CUSTOM
DPRINTLN(F("Device: WDS2_CUSTOM"));
#endif
#ifdef TWO_STATE
DPRINTLN(F("Configuration: TWO_STATE"));
#elif defined THREE_STATE
DPRINTLN(F("Configuration: THREE_STATE"));
#endif
}
};
typedef ADCThreeStateChannel<WdsHal, WDSList0, WDSList1, DefList4, PEERS_PER_CHANNEL> ChannelType;
#define CYCLETIME seconds2ticks(60ul * 60 * 12) // 2 Status/Alive Meldungen pro Tag
class DevType : public StateDevice<WdsHal, ChannelType, 1, WDSList0, CYCLETIME> {
public:
typedef StateDevice<WdsHal, ChannelType, 1, WDSList0, CYCLETIME> TSDevice;
DevType(const DeviceInfo& info, uint16_t addr)
: TSDevice(info, addr)
{
}
virtual ~DevType() {}
virtual void configChanged()
{
TSDevice::configChanged();
DPRINTLN(F("Config Changed: List0"));
uint8_t cycInfo = this->getList0().cycleInfoMsg();
DPRINT(F("cycleInfoMsg: "));
DDECLN(cycInfo);
uint8_t lowBatLimit = this->getList0().lowBatLimit();
DPRINT(F("lowBatLimit: "));
DDECLN(lowBatLimit);
battery().low(lowBatLimit);
uint8_t txDevTryMax = this->getList0().transmitDevTryMax();
DPRINT(F("transmitDevTryMax: "));
DDECLN(txDevTryMax);
}
};
WdsHal hal;
DevType sdev(devinfo, 0x20);
ConfigButton<DevType> cfgBtn(sdev);
void setup()
{
DINIT(57600, ASKSIN_PLUS_PLUS_IDENTIFIER);
sdev.init(hal);
sdev.channel(1).init(SENS_PIN_WET, SENS_PIN_WATER);
buttonISR(cfgBtn, CONFIG_BUTTON_PIN);
hal.battery.low(BAT_VOLT_LOW);
hal.battery.critical(BAT_VOLT_CRITICAL);
hal.battery.init(seconds2ticks(60ul * 60 * 24), sysclock); // 1x Batt.messung täglich
sdev.initDone();
}
void loop()
{
bool worked = hal.runready();
bool poll = sdev.pollRadio();
if (worked == false && poll == false) {
// deep discharge protection
// if we drop below critical battery level - switch off all and sleep forever
if (hal.battery.critical()) {
// this call will never return
hal.activity.sleepForever(hal);
}
// if nothing to do - go sleep
hal.activity.savePower<Sleep<>>(hal);
}
}
/*
SensorEventMsg 0x41
mit msg.append(0x1234):
<- 0E 01 A2 41 4929D3 435F5B 01 00 C8 12 34 - 243
-> 0A 01 80 02 435F5B 4929D3 00 - 368
waitAck: 01
InfoActuatorStatusMsg 0x10 ("CYCLETIME")
mit msg.append(0x1234):
<- 10 02 A2 10 4929D3 435F5B 06 01 C8 00 20 12 34 - 913
-> 0A 02 80 02 435F5B 4929D3 00 - 1038
waitAck: 01
*/
Hast Du die aktuelle Lib ? Sonst wird das prepareSend() nicht aufgerufen.
Ja, die habe ich. Ohne die ließ sich die CUSTOM Variante garnicht kompilieren.
Aktuellste Version der HMConfig_AskSinPPCustom ist auch installiert.
Er sendet 2 Byte für den Batteriewert. Du musst
$bat = $msg->payloadWord(3);
machen.
Läuft :-)
Ich danke dir für´s anpassen!
Mach bitte einen Pull-Request im GitHub, damit das dann auch für andere verfügbar ist
Zitat von: papa am 20 Januar 2021, 11:00:16
Mach bitte einen Pull-Request im GitHub, damit das dann auch für andere verfügbar ist
Erledigt!