Gardinenaktor Selbstbau - Fragen zu WOR und BlindStateMachine

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

Moderator: Co-Administratoren

Antworten
exp625
Beiträge: 6
Registriert: 13.05.2022, 19:08
System: CCU

Gardinenaktor Selbstbau - Fragen zu WOR und BlindStateMachine

Beitrag von exp625 » 16.10.2022, 14:29

Hallo zusammen,

ich tüftle seit einiger Zeit an einem Gardinenaktor für eine IKEA Hugad Gardinenstange. Idee des ganzen ist, die gesamte Platine mit Batterien in der Gardinenstange verschwinden zu lassen und 3D gedruckte Endkappen zu verwenden, um ein Nylonseil umlaufen zu lassen, welches die Gardinen mithilfe eines kleinen Getriebemotors öffnet oder schließt.

Die Erkennung der Endpositionen wird mithilfe von zwei Magnetschlitten und zwei Reed-Schalten realisiert. Die Platine ist als Prototyp gestaltet, bestellt und bestückt. Die 3D-Teile sind in Produktion.

Ich habe den bereits vorhandenen Sketch für einen Rollladenaktor https://github.com/pa-pa/AskSinPP/tree/ ... -LC-Bl1-FM für meinen Aktor anpassen.
Der Sketch funktioniert so weit, der Motor bewegt sich in die gewünschte Richtung, der Aktor wird erkannt und lässt sich einstellen.
Jetzt aber zu meinen Problemen, bei denen mir vielleicht jemand hier helfen kann.
  • Durch die Interrupts wird der Motor (die Gardine) an seiner Endpostion gestoppt. Ist einer der beiden Endschalter bereits geschlossen, bewegt sich der Motor auch korrekterweise nicht mehr. Das Level wird auch dann korrekt an die CCU gesendet. Trotzdem scheint die BlineStateMachine im Hintergrund weiterzulaufen (In der CCU ist weiterhin das Zahnrad bei "Letzte Änderung" zu sehen). Drückt man in der CCU die Stop Taste, wird auf einmal ein anderes Level zurückgemeldet. Gibt es irgendeine Möglichkeit die BlindeStateMachine beim Erreichen eines Endschalter vollständig zu stoppen. Weiterhin gibt es in der CCU für den Aktor die Einstellung "Anzahl der Fahrten bis zur automatischen Referenzfahrt". Könnte man die beiden Endschalter zu Referenzierung benutzen, sodass der Aktor die Fahrzeit selbstständig lernt?
  • Da es sich bei dem Projekt um einen Batterieaktor handelt, würde ich den Aktor gerne in den Sleep Modus versetzen und per WOR aufwachen lassen. Ich habe das Beispiel aus dem AskSinPP Projekt herangezogen und die entsprechenden Codezeilen in meinen Sketch integriert. Setze ich den SAVEPWR_MODE jedoch zu Sleep<> bekomme ich den Aktor nicht aufgeweckt. Hat hier jemand eine Idee, woran das liegen könnte? Muss der CCU aktiv mitgeteilt werden, dass ein Aktor WOR benutzt (bspw. duch custom RFTypes)?
Ich danke schonmal fürs Lesen und freue mich über mögliche Hilfestellung. Falls etwas unklar ist, dann stellt gerne eine Frage!
Viele Grüße

Code: Alles auswählen

#define EI_NOTEXTERNAL
#define NORTC
#define USE_WOR
// #define NDEBUG

#include <EnableInterrupt.h>
#include <AskSinPP.h>
#include <LowPower.h>
#include <Blind.h>
#include "tmBattery.h"

/**
 * Define the used pins, power saving mode and available peers per channel
 */
#define LED_PIN 4
#define CONFIG_BUTTON_PIN 8
#define MOTOR_ENABLE 5
#define MOTOR_DIR 3
#define MOTOR_VCC 9
#define CLOSE_SWITCH 7
#define OPEN_SWITCH 6

#define SAVEPWR_MODE Idle<>

#define PEERS_PER_CHANNEL 12

/**
 * Define the device info
 */
using namespace as;
const struct DeviceInfo PROGMEM devinfo = {
        {0x62, 0x51, 0x01},     // Device ID
        "EXP625BL01",                         // Device Serial
        {0x00,0x05},             // Device Model
        0x10,                              // Firmware Version
        as::DeviceType::BlindActuator,    // Device Type
        {0x01,0x00}                // Info Bytes
};

/**
 * Configure the used hardware
 */
typedef AvrSPI<10,11,12,13> RadioSPI;
typedef Radio<RadioSPI , 2> RadioType;
typedef StatusLed<LED_PIN> LedType;
typedef tmBatteryResDiv<A0, A2, 3102> BatteryType;
typedef AskSin<LedType,BatteryType,RadioType> Hal;
Hal hal;

DEFREGISTER(BlindReg0,MASTERID_REGS,DREG_INTKEY,DREG_CONFBUTTONTIME,DREG_LOCALRESETDISABLE, DREG_LOWBATLIMIT)

class BlindList0 : public RegList0<BlindReg0> {
public:
    BlindList0 (uint16_t addr) : RegList0<BlindReg0>(addr) {}
    void defaults () {
        clear();
        // intKeyVisible(false);
        confButtonTime(0xff);
        // localResetDisable(false);
    }
};

class BlChannel : public ActorChannel<Hal,BlindList1,BlindList3,PEERS_PER_CHANNEL,BlindList0,BlindStateMachine> {
public:
    typedef ActorChannel<Hal,BlindList1,BlindList3,PEERS_PER_CHANNEL,BlindList0,BlindStateMachine> BaseChannel;
    static BlChannel* instance;
    BlChannel () {}
    virtual ~BlChannel () {}

    virtual void switchState(uint8_t oldstate,uint8_t newstate, uint32_t stateDelay) {
        BaseChannel::switchState(oldstate, newstate, stateDelay);

        if( newstate == AS_CM_JT_RAMPON && stateDelay > 0) {
            if (!digitalRead(OPEN_SWITCH)) {
                DPRINTLN("Already Open");
                openSwitchTrigger();
            } else {
                motorOpen();
            }
        }
        else if( newstate == AS_CM_JT_RAMPOFF && stateDelay > 0) {
            motorClose();
            if (!digitalRead(CLOSE_SWITCH)) {
                DPRINTLN("Already Closed");
                closeSwitchTrigger();
            } else {
                motorClose();
            }
        }
        else {
            motorStop();
        }
    }

    static void openSwitchTrigger () {
        DPRINTLN("Open Switch Trigger");
        disableInterrupt(OPEN_SWITCH | PINCHANGEINTERRUPT);
        if (BlChannel::instance != nullptr) {
            BlChannel::instance->setState(AS_CM_JT_OFF, DELAY_INFINITE);
            BlChannel::instance->updateLevel(200);
        }
    }

    static void closeSwitchTrigger () {
        DPRINTLN("Close Switch Trigger");
        disableInterrupt(CLOSE_SWITCH | PINCHANGEINTERRUPT);
        if (BlChannel::instance != nullptr) {
            BlChannel::instance->setState(AS_CM_JT_OFF, DELAY_INFINITE);
            BlChannel::instance->updateLevel(0);
        }
    }

    void motorOpen () {
        DPRINTLN("Opening Curtain");
        digitalWrite(MOTOR_VCC,HIGH);
        digitalWrite(MOTOR_DIR,HIGH);
        digitalWrite(MOTOR_ENABLE,HIGH);
        enableInterrupt(OPEN_SWITCH | PINCHANGEINTERRUPT, openSwitchTrigger, FALLING);
    }

    void motorClose () {
        DPRINTLN("Closing Curtain");
        digitalWrite(MOTOR_VCC,HIGH);
        digitalWrite(MOTOR_DIR,LOW);
        digitalWrite(MOTOR_ENABLE,HIGH);
        enableInterrupt(CLOSE_SWITCH | PINCHANGEINTERRUPT , closeSwitchTrigger, FALLING);
    }

    void motorStop () {
        DPRINTLN("Stopping Curtain");
        digitalWrite(MOTOR_VCC,LOW);
        digitalWrite(MOTOR_DIR,LOW);
        digitalWrite(MOTOR_ENABLE,LOW);
        disableInterrupt(CLOSE_SWITCH | PINCHANGEINTERRUPT);
        disableInterrupt(OPEN_SWITCH | PINCHANGEINTERRUPT);
    }

    void init () {
        instance = this;
        pinMode(MOTOR_DIR,OUTPUT);
        pinMode(MOTOR_ENABLE,OUTPUT);
        pinMode(MOTOR_VCC,OUTPUT);
        pinMode(OPEN_SWITCH,INPUT_PULLUP);
        pinMode(CLOSE_SWITCH,INPUT_PULLUP);
        motorStop();
        BaseChannel::init();
    }
};

/**
 * Setup the device with channel type and number of channels
 */
typedef MultiChannelDevice<Hal,BlChannel,1,BlindList0> BlindType;

BlindType sdev(devinfo,0x20);
ConfigButton<BlindType> cfgBtn(sdev);
InternalButton<BlindType> btnup(sdev,1);
InternalButton<BlindType> btndown(sdev,2);
BurstDetector<Hal> bd(hal);

void initPeerings (bool first) {
    // create internal peerings - CCU2 needs this
    if(first) {
        sdev.channel(1).peer(btnup.peer(),btndown.peer());
    }
}

BlChannel * BlChannel::instance = nullptr;
void setup () {
    DINIT(9600,ASKSIN_PLUS_PLUS_IDENTIFIER);
    //storage().setByte(0,0);
    bool first = sdev.init(hal);
    sdev.channel(1).init();
    initPeerings(first);
    buttonISR(cfgBtn,CONFIG_BUTTON_PIN);
    bd.enable(sysclock);
    hal.activity.stayAwake(seconds2ticks(15));
    hal.initBattery(60UL * 60, 22, 19);
    sdev.initDone();
}

void loop() {
    bool worked = hal.runready();
    bool poll   = sdev.pollRadio();
    if (!worked && !poll) {
        if (hal.battery.critical()) {
            hal.activity.sleepForever(hal);
        }
        hal.activity.savePower<SAVEPWR_MODE>(hal);
    }
}

Benutzeravatar
stan23
Beiträge: 1959
Registriert: 13.12.2016, 21:14
System: Alternative CCU (auf Basis OCCU)
Wohnort: Altmühltal
Hat sich bedankt: 517 Mal
Danksagung erhalten: 307 Mal
Kontaktdaten:

Re: Gardinenaktor Selbstbau - Fragen zu WOR und BlindStateMachine

Beitrag von stan23 » 16.10.2022, 14:45

Hallo!
exp625 hat geschrieben:
16.10.2022, 14:29
Drückt man in der CCU die Stop Taste, wird auf einmal ein anderes Level zurückgemeldet. Gibt es irgendeine Möglichkeit die BlindeStateMachine beim Erreichen eines Endschalter vollständig zu stoppen. Weiterhin gibt es in der CCU für den Aktor die Einstellung "Anzahl der Fahrten bis zur automatischen Referenzfahrt". Könnte man die beiden Endschalter zu Referenzierung benutzen, sodass der Aktor die Fahrzeit selbstständig lernt?
Hast du denn die Fahrzeiten gemessen und in den Geräteeinstellungen eingetragen?
Das sollte erstmal ausreichen, denn bei einer Fahrt "auf Anschlag" läuft die Statemachine ein paar Sekunden länger, damit eben die Endschalter abschalten.
Die Referenzfahrt hat eine andere Bedeutung: wie oft du innerhalb von 1--99% fahren kannst, bevor automatisch erstmal auf 0% oder 100% gefahren wird, um Ungenauigkeiten auszugleichen.
exp625 hat geschrieben:
16.10.2022, 14:29
Hat hier jemand eine Idee, woran das liegen könnte? Muss der CCU aktiv mitgeteilt werden, dass ein Aktor WOR benutzt (bspw. duch custom RFTypes)?
Genau, der HM-LC-Bl1-FM ist nicht als "braucht einen Wakeup" bekannt und deswegen schickt die CCU auch keinen Burst.
Vielleicht ist ein anderer Gerätetyp besser geeignet, der hier scheint WOR zu benutzen:
https://github.com/pa-pa/AskSinPP/blob/ ... -Bl1-Velux
Das muss natürlich mit deinem Sketch vermischt werden :)
Viele Grüße
Marco

RaspberryMatic als VM auf einem NUC mit Proxmox und USB-Funkmodul
~80 Geräte (HM, HmIP, HMW, HBW, AskSin)

jp112sdl
Beiträge: 11043
Registriert: 20.11.2016, 20:01
Hat sich bedankt: 743 Mal
Danksagung erhalten: 1787 Mal
Kontaktdaten:

Re: Gardinenaktor Selbstbau - Fragen zu WOR und BlindStateMachine

Beitrag von jp112sdl » 16.10.2022, 14:46

exp625 hat geschrieben:
16.10.2022, 14:29
Muss der CCU aktiv mitgeteilt werden, dass ein Aktor WOR benutzt (bspw. duch custom RFTypes)?
Ja, rxmodes muss BURST enthalten
https://github.com/AskSinPP/asksinpp-we ... _ba.xml#L2

VG,
Jérôme ☕️

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

exp625
Beiträge: 6
Registriert: 13.05.2022, 19:08
System: CCU

Re: Gardinenaktor Selbstbau - Fragen zu WOR und BlindStateMachine

Beitrag von exp625 » 16.10.2022, 15:11

stan23 hat geschrieben:
16.10.2022, 14:45
Genau, der HM-LC-Bl1-FM ist nicht als "braucht einen Wakeup" bekannt und deswegen schickt die CCU auch keinen Burst.
Vielleicht ist ein anderer Gerätetyp besser geeignet, der hier scheint WOR zu benutzen:
https://github.com/pa-pa/AskSinPP/blob/ ... -Bl1-Velux
Das muss natürlich mit deinem Sketch vermischt werden :)
Vielen Dank! Das war eine sehr einfache Lösung. Mit der neuen DeviceID hat es auf Anhieb geklappt. Sogar ohne irgendetwas zu vermischen (Skeptische Freude :mrgreen: ). Wenn ich es richtig sehen, sendet der "Velux" Aktor ebenfalls keinen Batteriestatus?
stan23 hat geschrieben:
16.10.2022, 14:45
Hast du denn die Fahrzeiten gemessen und in den Geräteeinstellungen eingetragen?
Das sollte erstmal ausreichen, denn bei einer Fahrt "auf Anschlag" läuft die Statemachine ein paar Sekunden länger, damit eben die Endschalter abschalten.
Die Referenzfahrt hat eine andere Bedeutung: wie oft du innerhalb von 1--99% fahren kannst, bevor automatisch erstmal auf 0% oder 100% gefahren wird, um Ungenauigkeiten auszugleichen.
Jein, warte noch auf die 3D gedruckten Teile. Aber beim Testen klappt das natürlich mit der eingestellten Zeit.
Werden dann wohl die Zeit mit etwas Toleranz beaufschlagen, um die abfallende Batteriespannung auszugleichen.
Oder versuchen per PWM und aktuell gemessener Spannung eine konstante Geschwindigkeit einzustellen :lol:

exp625
Beiträge: 6
Registriert: 13.05.2022, 19:08
System: CCU

Re: Gardinenaktor Selbstbau - Fragen zu WOR und BlindStateMachine

Beitrag von exp625 » 16.10.2022, 17:29

jp112sdl hat geschrieben:
16.10.2022, 14:46
Ja, rxmodes muss BURST enthalten
https://github.com/AskSinPP/asksinpp-we ... _ba.xml#L2
Okay, da (obwohl die beiden RFTypes zwischen 0x005 und 0xf20a fast identisch sind) die HomeAssistent Integration mit dem Custom Device nicht klarkommt, habe ich die rxmodes einfach der bestehend rftypes des HM-LC-Bl1-FM hinzugefügt.
Jetzt funktioniert es mit WOR und in HomeAssistent.

Antworten

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