Modifikation HM-UNI-SEN-TEMP-DS1820

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

Moderator: Co-Administratoren

Antworten
harvey
Beiträge: 136
Registriert: 01.12.2013, 13:19
Danksagung erhalten: 3 Mal

Modifikation HM-UNI-SEN-TEMP-DS1820

Beitrag von harvey » 25.08.2018, 13:42

Hallo Forum,

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
Man kann schön sehen, dass die Adressen "rückwarts" gelesen werden, also niedrigste Stelle zuerst. Dann wird auch die aufsteigende
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);
  }
}
@jerome: Ich werde noch weiter optimieren, eventuell auch noch den WDS30, kommt dann als pullrequest, wenn Du Interesse hast.

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
Homematic raspberrymatic, iobroker, Asksinpp und Arduinos - rund 50 Geräte

jp112sdl
Beiträge: 12085
Registriert: 20.11.2016, 20:01
Hat sich bedankt: 847 Mal
Danksagung erhalten: 2139 Mal
Kontaktdaten:

Re: Modifikation HM-UNI-SEN-TEMP-DS1820

Beitrag von jp112sdl » 25.08.2018, 20:55

Hallo,

ich habe noch nicht ganz den Sinn verstanden.
Die Ds18b20.h-Sensorklasse hatten wir (also papa mehr als ich) erstellt, um nicht auf die externe Lib angewiesen zu sein und nur die nötigsten Funktionen einzubauen.

Letztendlich muss man sich die Arbeit ja nur 1x machen, um herauszufinden, welcher Sensor welchen Kanal benutzt.
Fühler in die Hand nehmen (oder in ein Glas warmes Wasser stecken), Strom an den Arduino anlegen, kurz warten bis Telegramm übertragen wurde und schauen, welcher die erhöhte Temperatur anzeigt. Das halt max. 8x.

Ein Problem ist es nur, wenn man mal einen Sensor austauscht. Dann könnte, bzw. wird die gesamte Sortierung durcheinander kommen.
Dafür habe ich jedoch keine (einfache) Lösung - wobei mir auch noch nie ein DS18B20 kaputt gegangen ist.

VG,
Jérôme ☕️

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

klassisch
Beiträge: 3974
Registriert: 24.03.2011, 04:32
System: Alternative CCU (auf Basis OCCU)
Hat sich bedankt: 110 Mal
Danksagung erhalten: 70 Mal

Re: Modifikation HM-UNI-SEN-TEMP-DS1820

Beitrag von klassisch » 25.08.2018, 21:08

Ja, genau das ist das Problem. Wenn ein Sensor getauscht wird oder wenn einer sich aus irgendwelchen Gründen nicht meldet. Dann kommt alles durcheinander.
Deshalb hate ich bei meinem ESP8266 Sketch auch mehrere synchrone Arrays mit der Sensor-ID und der ioBroker-Adresse. Und ich frage dann die Sensoren nach Id auf. Dann kann es nicht zu Verwechslungen kommen.
Aber die Verwaltung macht Aufwand, weil es dazu ein Userinterface braucht. Beim ESP8266 über Web-Interfache machbar, aber bei den HM-Teilen wird das eher mau. Vielleicht über ein aufwendiges XML oder im Hochlauf über die serielle Schnittstelle. Aber es braucht dann auch entsprechend EEPROM.

jp112sdl
Beiträge: 12085
Registriert: 20.11.2016, 20:01
Hat sich bedankt: 847 Mal
Danksagung erhalten: 2139 Mal
Kontaktdaten:

Re: Modifikation HM-UNI-SEN-TEMP-DS1820

Beitrag von jp112sdl » 25.08.2018, 21:39

Die Idee mit dem EEPROM ist an sich nicht schlecht. Vom Platz her braucht man ja nicht viel.

Man könnte initial die Adressen entsprechend der Erkennungsreihenfolge im EEPROM ablegen.
Wird nun ein Sensor ausgetauscht, rückt dieser an die Stelle der nun nicht mehr existierenden Adresse.
Alle anderen Adressen (wenn nun auch in anderer Reihenfolge / Position) können aufgrund ihrer initial gespeicherten Position im Array wieder zugeordnet werden und haben ihren fixen Platz.

VG,
Jérôme ☕️

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

harvey
Beiträge: 136
Registriert: 01.12.2013, 13:19
Danksagung erhalten: 3 Mal

Re: Modifikation HM-UNI-SEN-TEMP-DS1820

Beitrag von harvey » 25.08.2018, 22:33

Hi,
danke für eure Antworten!

Bei mir ist das Problem, dass die Sensoren an einem schwer zugänglichem Solarspeicher und den Zuleitungen
fest angebaut sind mit Verschraubung unter Isolierung. Da kann ich schlecht mal einen Sensor ins Wasser halten.

Ok, jetzt könnte ich auch kein Scratchpad beschreiben :-)

Der Sensortausch ist schon ein Problem, da rutscht alles hinter einem "niedrigen" Sensor nach hinten. Auch ein
sporadischer Sensorfehler (Sensor meldet sich nicht) führt bei der Zuordnung der Temperaturen der gefundenen Sensoren
zu den Kanälen in der WeatherMsg zu Randeffekten, wenn auf die Temperaturen etwas getriggert wird. Das könnte eine
Heizungssteuerung schon durcheinander bringen.

Ja, die Libraries u.a von papa sind völlig ok und auf Größe (besser auf Kleine) getrimmt. Aber z.B. eine Rundung
wäre wohl besser als reine Integerwandlung. int(temp * 10.0 + 0.5)

Ich habe mir ein altes 168-Arduino zum Lesen der Adressen gebaut, damit könnte man auch "schnell mal" die Userbytes beschreiben.
Aber der Vorschlag mit dem Array der Adressen hört sich super an, da ohne manuelle Aufgabe ausserhalb der echten Umgebung.
Wie bekommt man aus papas Lib die Adressen raus?

PS. manch anderer Sketch nutzt auch externe Libraries, z.B. der BME250, und soooo groß sind die Umterschiede im Speicher nicht (74% belegt).
Wenn ich mir ansehe, wieviel Text alleine in den Debugausgaben enthalten ist ... (vielleicht in ifdef DEBUG verpacken?)
PPS: Das Problem mit den Aussetzern löst sich glaube ich gerade: Die "alte" Vorbelegung von 0° für nicht erkannten Sensor
ist ja im zulässigen Bereich (ist -40 bis +125???), wird also als gültiger Wert entgegengenommen. Die -126.9°sind wohl ausserhalb und
werden ignoriert? Jedenfalls habe ich nach der Umstellung keine solchen Werte.

Schönes Wochenende!
ciao
Harvey
Homematic raspberrymatic, iobroker, Asksinpp und Arduinos - rund 50 Geräte

papa
Beiträge: 705
Registriert: 22.05.2018, 10:23
Hat sich bedankt: 24 Mal
Danksagung erhalten: 120 Mal

Re: Modifikation HM-UNI-SEN-TEMP-DS1820

Beitrag von papa » 26.08.2018, 07:46

Um die DEBUG-Ausgaben zu deaktivieren muss nur NDEBUG definiert werden. Dann ist alles weg.
Und noch ein Kommentar zur Rundung - kann man machen, ist aber bei einer Genauigkeit von 0,5°C des Sensors auch irgendwie mt Kanonen auf Spatzen geschossen. Im Prinzip sind die Nachkommastellen doch eh nur für die Optik :D
Anfragen zur AskSin++ werden nur im Forum beantwortet

harvey
Beiträge: 136
Registriert: 01.12.2013, 13:19
Danksagung erhalten: 3 Mal

Re: Modifikation HM-UNI-SEN-TEMP-DS1820

Beitrag von harvey » 26.08.2018, 09:39

Hi,

ja, die Ausgaben und DEBUG ... aber steht der Code nicht trotzdem im geflashten HEX-Image?
Oder verschwindet auch der Text z.B. "Temperaturen:" aus dem compilierten Code? Also Frage bei Größenproblemen...
Will ja nur lernen.

Nachkommastellen ... optik, ja, was ist schon eine exakte Temperatur :-)
Trotzdem sieht eine Darstellung besser aus, wenn sie kleine Schritte enthält.

PS. zu dem SCRATCHPAD habe ich noch ein paar Ideen, melde mich später, danke.
cu
Harvey
Homematic raspberrymatic, iobroker, Asksinpp und Arduinos - rund 50 Geräte

jp112sdl
Beiträge: 12085
Registriert: 20.11.2016, 20:01
Hat sich bedankt: 847 Mal
Danksagung erhalten: 2139 Mal
Kontaktdaten:

Re: Modifikation HM-UNI-SEN-TEMP-DS1820

Beitrag von jp112sdl » 26.08.2018, 10:01

harvey hat geschrieben:
26.08.2018, 09:39
Oder verschwindet auch der Text z.B. "Temperaturen:" aus dem compilierten Code? Also Frage bei Größenproblemen...
Will ja nur lernen.
Das sind Precompiler Anweisungen.
DPRINT, DDEC und DHEX werden nur "mit in den Code kompiliert", wenn nicht NDEBUG angegeben ist.

Kompiliere einmal den Sketch so wie er ist und füge mal an den Anfang des Sketchs #NDEBUG hinzu. Kompiliere erneut und du wirst den Unterschied in der Ausgabe der Größe sehen.

VG,
Jérôme ☕️

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

harvey
Beiträge: 136
Registriert: 01.12.2013, 13:19
Danksagung erhalten: 3 Mal

Re: Modifikation HM-UNI-SEN-TEMP-DS1820

Beitrag von harvey » 27.08.2018, 10:30

Hi,
danke, schaue ich mir gerne an.

Nur ein paar Gedanken zum DS18x20 und den Adressen:
- nun habe ich alle Sensoren schön verlegt, bin mir aber bei der Reihenfolge unsicher und kann nicht mehr einfach Sensor für Sensor messen
- ich habe ein Modul mit mehreren Sensoren (deren Reihenfolge ich kenne) und kombiniere das mit vorhandenen Senoren
- ich möchte mehr Messpunkte haben, kenne aber die Adressen der bereits verbauten Sensoren nicht (mehr)

Fall 1 tritt ein, wenn der Anbau der Sensoren aufwendig und ein Test nur mit viel Aufwand oder Zerstörung z.B. der Isolation möglich ist
Fall 2 ist z.B. ein zusätzlicher Wärmetauscher mit vier weiteren Sensoren, deren Adressen dann mit bereits vorhandenen Sensoren die Reihenfolge ändern
Fall 3 will einfach was zusätzlich messen ohne bisherige Sensorereihenfolge zu stören

Ach ja, ich will die Reihenfolge (in der WeatherMsg) nicht nachträglich ändern, da ich z.B. historische Daten in iobroker/influxDB habe
oder diverse Homematicscripte von Temperaturänderungen getriggert werden.

Als erstes Frage ich mich, wie erkenne ich, ob ich den Sensor schon kenne und "markiert und indiziert" habe:
- z.B. crc8 aus DeviceID(3 Byte), dabei 0x00, 0xff, 0xfe gegen anderen Wert tauschen (0xfe kommt gleich ...) = 1. UserByte.
Oder CRC(DeviceName), der ist einfacher im WebGUI zu finden.

Damit kann ein Sensor, der schonmal "woanders" markiert wurde als unbekannt/neu betrachtet und und jetzt neu indiziert werden.
Also jeder Sensor, dessen 1. UserByte nicht dem eigenen CRC(DeviceId) oder 0x00, 0xfe, 0xff gilt als "unbenutzt" und wird neu
einmal mit CRC und Index ins 1. und 2. UserByte beschrieben.

Vorgang:
es wird ein (der erste oder mehrere) Sensor angeschlossen, damit sensorcount höher als vorher: neue Sensor(en), bekommen im 2. UserByte den
niedrigste jemals gesehenen Index plus 1, der danach erhöht wird und rebootfest im atmel fest gespeichert wird (wie? und wie bleibt die Ziffer bei Neuprogrammierung das atmel erhalten?)
Gleiches gilt für jeden weiteren neuen Sensor (Fall 3), auch mehrere neue Sensoren können so behandelt werden, insbesonders auch wenn
ich doch alle Sensoren gleichzeitig anschließe, da ist es halt identisch mit Adressreihenfolge.
Will ich also die Reihenfolge fest und mir bekannt vorgeben, dann jeweils einen Sensor + reset. Ist es mir egal, einfach alle anschliessen.

Am Ende sind alle Sensoren mit CRC markiert und meinem Device zugeordnet und selbst mit Index versehen.
Will ich Sensoren manuell vorbereiten muss ich sie also manuell beschreiben, da kommt das "crc" 0xfe ins Spiel: diese Sensoren
werden auf allen Devices akzeptiert und nicht erneut mit eigenem CRC und eigenem Index beschrieben. Und sortieren sich
hinter die automatisch gefundenen Indexe ein. Will ich das mehrfach machen muss ich selbst auf den manuellen Index
achten, klar. (Fall 2).

Fällt ein Sensor aus erkenne ich -127° auf dem fehlerhaftem Sensor. Damit ist mir das crc (aus der homematic gelesen) und der Index
bekannt (z.b. der 3. Sensor). Nun kann ich einen solchen Sensor extern manuell beschreiben (automatisch ... hmmm sieht kompliziert aus).
Austausch des defekten Sensors ... und alles passt immer noch.

So kann ich "positionsinvariant" Sensoren austauschen, neue/unbekannte Sensoren automatisch "hinten" einreihen (einzeln oder auch mehrere),
einzelne oder Blöcke von vormarkierten Sensoren ohne DeviceID-Bindung hinten anreihen.

Sieht für mich so aus, als würde das vieles automatisch und voraussehbar gestalten ohne viel zuviel Aufwand.
Coding .... aktuell fehlt es an Routine (bei mir) und Routinen (Lesen/Schreiben UserBytes). Dann noch array der Sensoren zum
indizierten Eintrag in die WeatherMsg. Aber ich versuche das mal und melde mich wieder in ein paar Tagen.

cu
Harvey
Homematic raspberrymatic, iobroker, Asksinpp und Arduinos - rund 50 Geräte

harvey
Beiträge: 136
Registriert: 01.12.2013, 13:19
Danksagung erhalten: 3 Mal

Re: Modifikation HM-UNI-SEN-TEMP-DS1820

Beitrag von harvey » 31.08.2018, 15:08

Hi,

ein bischen weiter modifiziert ... das löst schon mal ein paar meiner Probleme.

1) Im ersten Schritt bei der Initialisierung die Adressen das gefundenen DS1820 im Speicher festhalten.
Diese Sensoren sind damit "bekannt". TODO: diese Info im eeprom reboot festbrennen.

2) Die Temperaturabfrage mit genau den gespeicherten Adressen durchführen.
Damit wird zu jeder bekannten Adresse die Temperatur in der Reihenfolge der initialen Erkennung durchgeführt.

3) Das Ergebis der Temperaturmessung prüfen:
- kommt -127 hat der Sensor Probleme, oder er fehlt. Gab es schon Messungen wird der letzte Wert gesendet. Gab es keine alte Messung
ist schlicht und einfach an dieser Position (in der Tabelle der Sensoradressen) gar kein Sensor gefunden worden, dann -127 senden

- kommt etwas anderes als -127 meldet der Sonsor schon mal eine Temperatur, das ist gut.
Ist die Temperaturabweichung zur letzten Messung >= 10 Grad wird der Mittelwert der letzten und der aktuellen Messung gesendet.
Dadurch werden kleiner Änderungen sofort, sehr große Änderung nur langsam nachgezogen. Ein gültiger Wert
wird für den nächsten Meszyklus gespeichert (array sensors[MAX_SENSORS]);.

Im Ergebnis:
Fällt ein initial bekannter Sensor aus (Messung mit dieser Adresse liefert jetzt -127) wird dauernd der letzte gültige Wert gesendet.
Die Reihenfolge der Sensoren ändert sich nicht, also ursprünglich "dahinter" liegende Sensoren (mit höherer Adresse)
rutschen nicht nach vorne, sie senden weiter auf ihrer Position (Index, Reihenfolge), da ja auf der ausgefallenen Position
der letzte Wert immer wiederholt wird.

Grobe Temperaturausreißer werden durch Mittelung mit dem letzten Wert langsam angepasst, bis die Änderung unterhalb der
Schwelle (z.B. 10 Grad, fest eingebaut im Sketch) ist.

Nachteil:
Da die Erkennung eines ausgefallenen Sensors in der Liste der ursprünglich erkannten Sensoren über die Adresse läuft
muss die Ardiuno Library "DallasTemperature" verwendet werden. Damit geht auch die Temperaturabfrage mit einer
vorgegebenen Adresse und nicht einfach in der jetzt gefundenen Reihenfolge.

TODO:
Die Sensoren "auf Wunsch" rebootfest im EEPROM lagern.
Dazu muss man diesen Wunsch "aussprechen" können, etwa durch den normalen Anlernvorgang, also der
kurze Tastendruck "anlernen". Dies erscheint mir logisch, da es auch um das Anlernen der Sensoren geht
und ein zusätzliches Anlernen die Zentrale nicht stört bzw. zum Abholen von Konfigurationsänderungen sowieso
notwendig ist. (Hmmmm, könnten die Konfigurationsänderungen nicht auch nach dem nächsten Temperaturtelegramm
empfangen werden? Wahrscheinlich nicht (lazyConfig?), da ja nichts (auch kein Ack) empfangen wird.

Man muss diese Einträge im EEPROM aber auch wieder loswerden. Hier kann ich mir den langen (aber einmaligen) Druck
auf die Anlerntaste vorstellen. Nicht zweimal lange Drücken, da dies eine kompletter Reset ist (inkl. Direktverknüpfung?).
Aber ein langer Tastendruck sollte reichen. Allerdings habe ich dazu noch nichts in der Library gefunden, muss noch weiter suchen.

Ach ja, die Codeschnipsel, viel kommentiert und nicht optimiert, passen für WDS30-OT2 und 8fach_DS1820:
Speichern der gefundenen Adressen:

Code: Alles auswählen

DallasTemperature tsensors(&oneWire);
DeviceAddress TAddress[MAX_SENSORS];
...
      TSDevice::init(hal);

      tsensors.begin();
      DPRINTLN("HM-WDS30-OT2-DS1820-Dallas");
      sensarray.sensorcount = tsensors.getDS18Count();
      DPRINT("Found "); DDEC(sensarray.sensorcount); DPRINTLN(" DS1820 Sensors:");
      for (int i = 0; i < sensarray.sensorcount; i++) {
        tsensors.getAddress(TAddress[i],i);
        DDEC(i); DPRINT(": ");
        DHEX(TAddress[i][0]); DPRINT(" ");
        for (uint8_t ii = 1; ii < 6; ii++)
        {
          DHEX(TAddress[i][ii]); DPRINT(".");
        }
        DHEX(TAddress[i][6]); DPRINT(" ");
        DHEX(TAddress[i][7]); DPRINTLN("");
      }  
Damit stehen alle gefundenen Adressen im array TAdress[MAX_SENSORS].

Und nun die Messung mit der Überprüfung der Messergebnisse:

Code: Alles auswählen

         DPRINTLN(F("Temperaturen:"));
            for (int i = 0; i < sensorcount; i++) {

           //   DHEXLN(TAddress[i][1]);  // nur so zur Identifizierung
              temp = int(((tsensors.getTempC(TAddress[i])*10)+.5));
           //   DDECLN(temp);            // das ist gelesen worden
              if (temp > -126) {    // eine temperatur gemesssen wurde
           //   DPRINT("/"); DDEC(temp); DPRINT("-"); DDEC(sensors[i]); DPRINT("="); DDEC(abs(temp - sensors[i])); DPRINT("/ ");
                if ((sensors[i] < -126) || (abs(temp - sensors[i]) < 100)){ // wenn es keine alte temperatur gibt oder die differenz unter 10 Grad liegt übernehmen
                  sensors[i] = temp;
           //     DPRINT ("fast ");
                } else { // es gibt eine alte temperatur und differenz >= 10 Grad
                  sensors[i] = (sensors[i] + temp) /2;   // Mittelwert
           //    DPRINT ("slow ");
                }
                DDEC(sensors[i]); DPRINT(" <- ");
                DDEC(tsensors.getTempC(TAddress[i])); DPRINTLN(":");
            
              } else {     // Fehlmessung
                if (sensors[i] > -126) {    // es gibt eine alte gueltige Messung, diese verwenden (flatline)
                  DPRINT("old: "); DDECLN(sensors[i]);
                } else {
                  DPRINTLN(" - ");    // kein Sensor vorhanden
                }
              }
            }
            DPRINTLN("");
Ein bischen roh, aber ich denke, man kann die Idee sehen.

Das ist jetzt nicht die "ganz tolle" Lösung mit variabler Reihenfolge der Sensoren, aber erstmal verschieben sich keine Messwerte
mehr bei einem (temporären) Sensorfehler. Ist der Sensor defekt muss er getauscht werden und die Reihenfolge erneut
manuell in Erfahrung gebracht werden.

Fragen jederzeit gerne.
Und wer Ideen zum rebootfesten Speichern und manuellen resetten des Speichers zum neueinlesen hat ebenfalls gerne.

cu
Harvey
Homematic raspberrymatic, iobroker, Asksinpp und Arduinos - rund 50 Geräte

Antworten

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