Anpassung für blinkende Lichterkette

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

Moderator: Co-Administratoren

Corvinius
Beiträge: 8
Registriert: 05.02.2022, 12:24
System: Alternative CCU (auf Basis OCCU)

Anpassung für blinkende Lichterkette

Beitrag von Corvinius » 01.05.2022, 20:38

Hello Zusammen,

vielen Dank, dass ich mit im Forum sein darf. Ich nutze aktuell RaspberryMatic als CCU und hab schon einige Geräte im Einsatz.
Nun habe ich mir vor Kurzem ein paar schöne Garten-Lichterketten besorgt, welche mit Solar auf 3,3V Basis funktionieren. Gern würde ich die via Homekit steuern. Mein erster Ansatz über einen ESP8266 haben theoretisch funktioniert aber der Batteriverbrauch war zu hoch.
Daher habe ich mich auf AskSin++ zurückbesonnen. Mein erster Versuch mit dem Batteri-Aktor von Papa ( https://github.com/pa-pa/AskSinPP/blob/ ... BA-PCB.ino ) war auch gut, jedoch habe ich folgendes "Problem" und würde mich über eure Hilfe sehr freuen:
Die Lichterkette hat nur einen Schalter, welcher quasi Programme "durchschaltet" -> also 1x Drücken An, noch mal Drücken langsam blinken, noch mal schnell blinken usw. bis "Aus".
Gern möchte ich das natürlich abbilden und mit verarbeiten, aber da scheitert es leider. Im ESP hatte ich im loop() quasi eine "Zählfunktion" und habe im Interval den A0 gemessen, ob Spannung anliegt. Wenn über 20 Durchläufe alle 1 sec 20 Werte "high" waren, wusste ich, die Lampe ist an. Wenn 20 Werte "low" waren war sie aus, wenn weniger als 20 aber mehr als 0 waren war die Lampe grad irgendwie am Blinken und ich konnte über den Schalter quasi digital so lange drücken, bis sie wieder an oder aus war. Somit ist quasi die "Blinken" Funktion nicht mehr da, würde mir aber auch reichen.
Quasi so…

Code: Alles auswählen

 unsigned long currentMillis = millis();

  if ((unsigned long)(currentMillis - previousLampStateChange) >= timeIntervalLampStateChange)
  {
    previousLampStateChange = currentMillis;
    getLampStatus();
  }
  
  …
  
  void getLampStatus() {
  int inputState = digitalRead(statusInput);
  statusCounter = statusCounter + inputState;
  counter++;

  if (counter == 20 && statusCounter == 0) {
    Serial.println("Lamp On");
    counter = 0;
    statusCounter = 0;
    globalLampStatus = lampOn;
    sendMQTTdata("currentStatus", "lampOn");
  }

  if (counter == 20 && statusCounter == 20) {
    Serial.println("Lamp Off");
    counter = 0;
    statusCounter = 0;
    globalLampStatus = lampOff;
    sendMQTTdata("currentStatus", "lampOff");
  }

  if (counter == 20 && statusCounter < 20 && statusCounter > 0) {
    Serial.println("Lamp blinking");
    counter = 0;
    statusCounter = 0;
    globalLampStatus = lampBlinking;
    sendMQTTdata("currentStatus", "lampBlinking");
  }

  if (counter > 20) {
    counter = 0;
    statusCounter = 0;
  }

}
  

Meine Frage wäre jetzt - wie kann ich diese Funktion quasi oben in den AskSin++ Sketch einbauen, sodass ich die Lampe entsprechend steuern kann. Grob gesagt: wenn jemand den Knopf am Gehäuse drückt, soll sie halt auch angehen. Und ich will dann am HomeKit Gerät sehen, dass die Lampe an ist. Und wenn jemand noch mal drückt oder ich sie halt via HomeKit ausschalte, muss der Sketch quasi "durchschalten", bis sie aus ist.

Sollte es wieder meinen Erwartungen möglich sein, eine "blinkende" Lampe in HomeKit mit einzubauen, wäre das toll. Aber ich hab bisher nur farbige Lampen gesehen…

Ich hoffe, ich hab niemanden verwirrt :roll: :roll: und ihr könnt mir helfen :?:
Vielen Dank im Voraus und einen schönen Abend.

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

Re: Anpassung für blinkende Lichterkette

Beitrag von papa » 02.05.2022, 08:52

Im Prinzip sollte das Erkennen des aktuellen Zustandes mit der Alarm-Klasse recht einfach zu machen sein.
Grob könnte das so aussehen - ohne Deine Logik:

Code: Alles auswählen

class StatusMon : public Alarm {
  int state; // 0=off, 1=on, 2=blink
public:
  StatusMon () : Alarm(0,true), state(0) {
    // init you input pin
  }
  virtual ~StatusMon () {}

  virtual void trigger (AlarmClock& clock) {
    // read input pin and update counters
    // and store state in member

    // reactivate alarm
    set(millis2ticks(100));
    clock.add(*this);
  }

  void start (AlarmClock& clock) {
    trigger(clock);
  }
  
  int getState () {
    return state;
  }
};
Dann muss das nur noch als Object im Sketch angelegt und im setup() aktiviert werden.

Code: Alles auswählen

StatusMon statusmonitor;

void setup () {
  // ... you setup code
  
  statusmonitor.start();
}
Anfragen zur AskSin++ werden nur im Forum beantwortet

Corvinius
Beiträge: 8
Registriert: 05.02.2022, 12:24
System: Alternative CCU (auf Basis OCCU)

Re: Anpassung für blinkende Lichterkette

Beitrag von Corvinius » 30.05.2022, 14:00

Hallo Papa,

vielen Dank für die rasche Antwort!

Ich hab es mal versucht, aber scheinbar klappt da was noch nicht - vielleicht könntest du mir bitte etwas helfen?
Nachdem ich den Sketch wieder hochgeladen habe (ohne die neue Logik) habe ich das Gefühl, dass er Pin 6 und 8 zusammenwirft. Also ich kann quasi über die CCU den Pin nicht steuern, aber wenn ich auf den Button an Pin 8 drücke, wird der Pin 6 getriggert und er zeigt in der CCU auch die Zustandsänderung mit an (ich verwende grade dieses Hardware-Setup: https://wiki.gorjup.de/doku.php?id=public:fhem_asksinpp )
EDIT: scheint wieder zu klappen - das Verhalten trat nur solange auf, wie der TTL-Converter mit verbunden war (wollte gern debuggen... :? )
EDIT2: klappt doch nicht - auch ohne TTL… Schaltung quasi aktuell nur über Button an Pin8 möglich.. scheinbar klemmt da was :?:


Bzgl. des anderen Themas habe ich mich versucht und bin wohl in der Vererbung irgendwo stecken geblieben :-(
Irgendwie komme ich nicht auf die Alarm bzw. AlarmClock Funktion da sie anscheinen nicht deklariert ist:

Code: Alles auswählen

In file included from /Users/XXXX/bb_source/AskSinPP_1channelActorBattery/StatusMon.cpp:1:0:
StatusMon.h:10:32: error: expected class-name before '{' token
 class StatusMon : public Alarm {
                                ^
StatusMon.h:20:27: error: 'AlarmClock' has not been declared
     virtual void trigger (AlarmClock& clock);
                           ^~~~~~~~~~
StatusMon.h:21:17: error: 'AlarmClock' has not been declared
     void start (AlarmClock& clock);
                 ^~~~~~~~~~
/Users/XXXX/bb_source/AskSinPP_1channelActorBattery/StatusMon.h: In constructor 'StatusMon::StatusMon(int)':
StatusMon.h:14:29: error: class 'StatusMon' does not have any field named 'Alarm'
     StatusMon (int pinNo) : Alarm(0, true), state(0) {
                             ^~~~~
/Users/XXXX/bb_source/AskSinPP_1channelActorBattery/StatusMon.cpp: At global scope:
StatusMon.cpp:5:1: error: redefinition of 'StatusMon::StatusMon(int)'
 StatusMon::StatusMon(int pinNo) : Alarm{
 ^~~~~~~~~
In file included from /Users/XXXX/bb_source/AskSinPP_1channelActorBattery/StatusMon.cpp:1:0:
/Users/richard/bb_source/AskSinPP_1channelActorBattery/StatusMon.h:14:5: note: 'StatusMon::StatusMon(int)' previously defined here
     StatusMon (int pinNo) : Alarm(0, true), state(0) {
     ^~~~~~~~~
StatusMon.cpp:10:21: error: declaration of '~StatusMon' as non-member
 virtual ~StatusMon () {}
                     ^
StatusMon.cpp:12:1: error: 'virtual' outside class declaration
 virtual void StatusMon::trigger (AlarmClock& clock) {
 ^~~~~~~
StatusMon.cpp:12:34: error: variable or field 'trigger' declared void
 virtual void StatusMon::trigger (AlarmClock& clock) {
Könntest du oder jemand anders bitte noch mal drüberschauen?
Vielen Dank im Voraus.

anbei die files:

Code: Alles auswählen

// StatusMon.h
#ifndef StatusMon_h
#define StatusMon_h

#include <Arduino.h>
#include <AskSinPP.h>
#include <Alarm.h>


class StatusMon : public Alarm {
  private:
    int state; // 0=off, 1=on, 2=blink
  public:
    StatusMon (int pinNo) : Alarm(0, true), state(0) {
      int counter;
      int statusCounter;
    }
    virtual ~StatusMon ();

    virtual void trigger (AlarmClock& clock);
    void start (AlarmClock& clock);
    int getState ();
};

#endif
und

Code: Alles auswählen

// StatusMon.cpp
#include "StatusMon.h"
#include <Alarm.h>


StatusMon::StatusMon(int pinNo){
  _pinNumber = pinNo;
  pinMode(_pinNumber; INPUT);
}

virtual ~StatusMon () {}

virtual void StatusMon::trigger (AlarmClock& clock) {
  // read input pin and update counters
  // and store state in member
  int inputState = digitalRead(_pinNumber);
  statusCounter = statusCounter + inputState;
  counter++;

  if (counter == 20 && statusCounter == 0) {
    DPRINT(F("Lamp On"));
    counter = 0;
    statusCounter = 0;
    state = 1;
  }

  if (counter == 20 && statusCounter == 20) {
    DPRINT(F("Lamp Off"));
    counter = 0;
    statusCounter = 0;
    state = 0;
  }

  if (counter == 20 && statusCounter < 20 && statusCounter > 0) {
    DPRINT(F("Lamp blinking"));
    counter = 0;
    statusCounter = 0;
    state = 2;
  }

  if (counter > 20) {
    counter = 0;
    statusCounter = 0;
  }

  // reactivate alarm
  set(millis2ticks(100));
  clock.add(*this);
}

void StatusMon::start (AlarmClock& clock) {
  trigger(clock);
}

int StatusMon::getState () {
  return state;
}

Und im Hauptcode dann:

Code: Alles auswählen

#include "StatusMon.h"
StatusMon statusmonitor(7);

...

void setup () {
…
statusmonitor.start();
}


was ich bin jetzt verstanden habe:
- du erzeugst eine neue Klasse (SubClass) 'StatusMon' welche von der Klasse Alarm erbt.
- diese beinhaltet eine 'state' variable, die via "getState()" abgerufen werden kann
-

Code: Alles auswählen

StatusMon () : Alarm(0, true), state(0) {
an dieser Stelle scheinen die Klasseneigenschaften erzeugt zu werden, daher sollten dort alle benötigten Variablen deklariert werden.
- die Methode 'trigger' ist quasi das, was ich über die 'millies()' gelöst hatte -> diese Methode wird alle X Millisekunden ('millis2ticks(100)') aufgerufen und durchlaufen.
- somit kann ich in der trigger-Methode meine "Zähl-Logik" einbauen und ausführen und darüber die state-Variable setzen.
- der Alarm wird somit alle X Millisekunden ausgeführt.
- wenn ich alles richtig gemacht habe, müsste es einen neuen Datenpunkt innerhalb des Gerätes auf der CCU geben mit Namen "STATE" welcher dann den Wert 0,1,2 haben kann (siehe Foto:
Bildschirmfoto 2022-05-30 um 17.37.29.png
)…

passt das soweit?

Corvinius
Beiträge: 8
Registriert: 05.02.2022, 12:24
System: Alternative CCU (auf Basis OCCU)

Re: Anpassung für blinkende Lichterkette

Beitrag von Corvinius » 05.06.2022, 18:47

Hello Zusammen,

so kleines Update -> hab mich mit nem Freund noch mal drangesetzt, der C++ deutlich besser kann als ich :mrgreen:

anbei die beiden files - er kompiliert sauber. Ich kann wohl auch wieder über die UCC schalten (ggf. wäre es cooler, wenn der Typ ein "Taster" wäre, statt einem Switch… wie geht das :?:

Code: Alles auswählen

// StatusMon.h
#ifndef StatusMon_h
#define StatusMon_h

#include <Arduino.h>
#include <AskSinPP.h>
#include <Alarm.h>

enum State { 
  Off = 0,
  On = 1,
  Blink = 2,
};

class StatusMon : public as::Alarm {
  private:
    State state;
  public:
    StatusMon ();
    ~StatusMon();

    uint32_t counter;
    uint32_t statusCounter;

    virtual void trigger(as::AlarmClock& clock);
    void start(as::AlarmClock& clock);
    State getState();
};

#endif
und dann noch

Code: Alles auswählen

// StatusMon.cpp
#include <Arduino.h>
#include "StatusMon.h"
#include <Alarm.h>

static uint16_t AlarmPin = 7;

StatusMon::StatusMon() : Alarm(0, true), state(0) {
  pinMode(AlarmPin, INPUT);
}

StatusMon::~StatusMon() {}

void StatusMon::trigger (as::AlarmClock& clock) {
  // read input pin and update counters
  // and store state in member
  auto inputState = digitalRead(AlarmPin);
  statusCounter = statusCounter + inputState;
  counter++;

  if (counter == 20 && statusCounter == 0) {
    DPRINT(F("Lamp On"));
    counter = 0;
    statusCounter = 0;
    state = 1;
  }

  if (counter == 20 && statusCounter == 20) {
    DPRINT(F("Lamp Off"));
    counter = 0;
    statusCounter = 0;
    state = 0;
  }

  if (counter == 20 && statusCounter < 20 && statusCounter > 0) {
    DPRINT(F("Lamp blinking"));
    counter = 0;
    statusCounter = 0;
    state = 2;
  }

  if (counter > 20) {
    counter = 0;
    statusCounter = 0;
  }

  // reactivate alarm
  set(millis2ticks(100));
  clock.add(*this);
}

void StatusMon::start (as::AlarmClock& clock) {
  trigger(clock);
}

State StatusMon::getState () {
  return state;
}
Was ich (doch) noch nicht verstanden habe -> wie/wo komme ich dann an den Status-Wert? Muss ich den in der loop() noch mitschicken? Habe dort mal testweise so was eingebaut

Code: Alles auswählen

  if ( worked == false && poll == false ) {

    int currentState = statusmonitor.getState();
    if (previousLampState != currentState) {
      previousLampState = currentState;
      DPRINT(F("Lamp State: "));
      DPRINTLN(currentState);
    }
    // some battery code comes here…
    …
    }
aber dort kommt keine Status-Änderung an sondern immer nur "0"…

Vielen Dank für eure Hilfe!

Corvinius
Beiträge: 8
Registriert: 05.02.2022, 12:24
System: Alternative CCU (auf Basis OCCU)

Re: Anpassung für blinkende Lichterkette

Beitrag von Corvinius » 05.06.2022, 22:34

Nachtrag:

Habe mal ein bissle versucht zu debuggen… :twisted:
in der StatusMon.cpp wird "trigger" einmal im setup aufgerufen, aber danach nicht mehr im Interval - hatte es so verstanden, dass die Funktion sich selbst wieder aufrufen sollte mit

Code: Alles auswählen

  set(millis2ticks(100));
  clock.add(*this);
Wird sie aber leider nicht. Daher wird quasi nur einmal der Status gemessen und danach nie wieder. Wenn ich testweise darunter ein "trigger(clock);" schreibe, komme ich in eine endlosschleife (logischerweise) und dort werden auch die Inputwerte sauber eingelesen und verarbeitet.
Hoffe, das hilft jemandem weiter - mir leider aktuell (noch) nicht :? :oops:

Danke für eure Unterstützung!

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

Re: Anpassung für blinkende Lichterkette

Beitrag von jp112sdl » 05.06.2022, 22:39

Corvinius hat geschrieben:
30.05.2022, 14:00
- wenn ich alles richtig gemacht habe, müsste es einen neuen Datenpunkt innerhalb des Gerätes auf der CCU geben mit Namen "STATE" welcher dann den Wert 0,1,2 haben kann (siehe Foto: Bildschirmfoto 2022-05-30 um 17.37.29.png )…
Wo soll der herkommen?
Die CCU kennt den nicht.

VG,
Jérôme ☕️

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

Corvinius
Beiträge: 8
Registriert: 05.02.2022, 12:24
System: Alternative CCU (auf Basis OCCU)

Re: Anpassung für blinkende Lichterkette

Beitrag von Corvinius » 06.06.2022, 11:30

Hi Jérôme,

vielen Dank für deine Antwort. Wie würdest du dieses Thema angehen?

Im Zweifel muss es ja nicht "blinkend" sein, finde das eh bissle nervig. Aber wenn das mit der Alarm-Klasse sauber geht, dann habe ich verstanden, dass ich darüber einen "Timer" bekomme, um etwas im Interval zu überprüfen (z.B: ob's leuchtet oder blinkt oder aus ist). Dann kann ich auch dort eine Methode einbauen, die so lange "weiterschaltet" bis es halt an oder aus ist - damit der Schalter Konsistenz hat. Das müsste doch gehen, korrekt?
Also: wenn "an", dann "an"… wenn "aus" dann nutze die Alarmklasse und "drücke" solange den Schalter mit einer kleinen Verzögerung, bis es "aus" ist… Würde das gehen?

Wo liegt mein Fehler, dass die Alarmklasse nicht periodisch aufgerufen wird oder habe ich etwas anderes noch übersehen?

Vielen Dank für eure Unterstützung.

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

Re: Anpassung für blinkende Lichterkette

Beitrag von jp112sdl » 06.06.2022, 12:11

Hab das Ziel noch nicht verstanden. Ist mir auch ein bisschen zu viel Text ^^

Der HM-LC-Sw1-BA-PCB hat 1 Kanal, der kann EIN oder AUS.
Bau doch diese ganze Taster-Blink-Logik aus deiner Lichterkette aus und schalte die LEDs über einen FET.
Über die Statemachine lässt sich auch ein Blinken realisieren. Per Direktverknüpfung mit Einschaltdauer/Ausschaltdauer/Verweildauer ein/aus

VG,
Jérôme ☕️

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

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

Re: Anpassung für blinkende Lichterkette

Beitrag von papa » 06.06.2022, 21:23

Corvinius hat geschrieben:
05.06.2022, 22:34
Nachtrag:

Habe mal ein bissle versucht zu debuggen… :twisted:
in der StatusMon.cpp wird "trigger" einmal im setup aufgerufen, aber danach nicht mehr im Interval - hatte es so verstanden, dass die Funktion sich selbst wieder aufrufen sollte mit

Code: Alles auswählen

  set(millis2ticks(100));
  clock.add(*this);
Wird sie aber leider nicht. Daher wird quasi nur einmal der Status gemessen und danach nie wieder. Wenn ich testweise darunter ein "trigger(clock);" schreibe, komme ich in eine endlosschleife (logischerweise) und dort werden auch die Inputwerte sauber eingelesen und verarbeitet.
Hoffe, das hilft jemandem weiter - mir leider aktuell (noch) nicht :? :oops:

Danke für eure Unterstützung!
100 millis sind ganz schön kurz. Per Default macht die Sysclock nur 100 Ticks pro Sekunde. Was kommt den bei millis2ticks(100) raus ?
Vielleicht mal ein

#define TICKS_PER_SECOND 500UL

an den Sketchanfang.
Anfragen zur AskSin++ werden nur im Forum beantwortet

Corvinius
Beiträge: 8
Registriert: 05.02.2022, 12:24
System: Alternative CCU (auf Basis OCCU)

Re: Anpassung für blinkende Lichterkette

Beitrag von Corvinius » 06.06.2022, 23:29

Hi, vielen Dank ihr beiden, werde ich testen und berichten.

@Jérôme: ich versuche eine gekaufte Solar-Lichterkette zu steuern. Wollte ungern die Solar-Laderegler, Tiefentladeschutz usw. nachbauen, aber ist vllt. am Ende weniger aufwending -> Ladeboard, Tiefentladeschutz, Mosfet und gut ist.

Bliebe noch eine Frage: kann ich den Scetch so anpassen (oder gibt's nen anderen), sodass ich noch einen Taster mit anbauen kann, der ebenso das Licht schaltet. Also einen 1-Channel-Batterie-Aktor so wie ich habe, der in der CCU als (Licht-)Schalter angezeigt wird, der aber auch (zusätzlich) am Gerät selbst geschaltet werden kann - quasi wie eine Kreuzschaltung am Wohnzimmerlicht :D

Antworten

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