Asksin++ - Langen Tastendruck und gleichzeitigen Druck von 2 Tasten abfragen?

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

Moderator: Co-Administratoren

Antworten
OliR
Beiträge: 4
Registriert: 16.12.2021, 17:46
System: Alternative CCU (auf Basis OCCU)
Hat sich bedankt: 2 Mal

Asksin++ - Langen Tastendruck und gleichzeitigen Druck von 2 Tasten abfragen?

Beitrag von OliR » 30.12.2021, 13:55

Hallo,
ich baue einen Asksin++-Aktor auf, um Somfy IB Rolladen-Aktoren an Homematic anzubinden.
Dazu benötige ich etwas Hilfe bei der Asksin++ Programmierung/Konfiguration.

Die Somfy IB (Installation Bus oder so ähnlich) Ansteuerung sieht folgendermassen aus:
Es gibt drei Leitungen:
1) common (+30V)
2) up
3) down

Um eine Aktion auszuführen, weden up, down oder up+down gleichzeitig kurz oder lang mit common verbunden:
0) up + down nicht mit common verbunden => nichts passiert
1) up kurz mit common verbunden => Rolladen fährt hoch, wenn nicht am Somfy Aktor die Automatik ausgeschaltet wurde
2) down kurz mit common verbunden => Rolladen fährt runter, wenn nicht am Somfy Aktor die Automatik ausgeschaltet wurde
3) up+down kurz mit common verbunden => Rolladen stoppt, wenn nicht am Somfy Aktor die Automatik ausgeschaltet wurde
4) up lang mit common verbunden => Rolladen fährt immer hoch
5) down lang mit common verbunden => Rolladen fährt immer runter
6) up+down lang mit common verbunden => Rolladen stoppt immer

entsprechend müssen vom Asksin++ Aktor auch die IB-Pulse generiert werden.


Ich habe bereits eine Platine aufgebaut, die in eine Unterputzdose passt:
Bild
Die Spannungsversorgung (30V) kann man sich vom Somfy Aktor holen, so dass nur mit Kleinspannung gearbeitet wird.

Ich habe den Sketch HM-LC-Bl1-FM von "papa" verwendet und folgende Änderungen durchgeführt:
1) Pindefinitionen angepasst
2) Da Somfy-IB high-active auf die Buttons geführt wird, habe ich die Buttons high-active definiert:

Code: Alles auswählen

InternalButton<BlindType,LOW,HIGH,INPUT> btnup(sdev,1);
InternalButton<BlindType,LOW,HIGH,INPUT> btndown(sdev,2);
3) Ich habe eine Funktion geschrieben, die per Alarm nach definierter Zeit die Ausgänge wieder auf Low setzt (siehe OutputPulseReset.h) und diese in motorUp, motorDown und motorStop am Ende hinzugefügt.
4) ich habe switch_state so geändert, dass motorStop nur unter folgender Bedingung aufgerufen wird:

Code: Alles auswählen

else if(( newstate == AS_CM_JT_ON && stateDelay > 0 ) || ( newstate == AS_CM_JT_OFF && stateDelay > 0 )
Hier der vollständige Code:

Code: Alles auswählen

//- -----------------------------------------------------------------------------------------------------------------------
// AskSin++
// 2017-12-14 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
// ci-test=yes board=328p aes=no
//- -----------------------------------------------------------------------------------------------------------------------

// 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 <Blind.h>
#include "OutputPulseReset.h"


// we use a Pro Mini
// Arduino pin for the LED
// D4 == PIN 4 on Pro Mini
#define LED_PIN 4
// Arduino pin for the config button
// B0 == PIN 8 on Pro Mini
#define CONFIG_BUTTON_PIN 8


// define up and down pins for Somfy IB Bus to device
#define UP_PIN 16
#define DOWN_PIN 17

// define button pins for Somfy IB Bus input from central button
#define UP_BUTTON_PIN 15
#define DOWN_BUTTON_PIN 14

// number of available peers per channel
#define PEERS_PER_CHANNEL 12

// all library classes are placed in the namespace 'as'
using namespace as;

OutputPulseReset PulseReset;

// define all device properties
const struct DeviceInfo PROGMEM devinfo =
{
    {0x59,0x32,0xaf},              // Device ID
    "papa5932af",                  // Device Serial
    {0x00,0x05},                   // Device Model
    0x24,                          // Firmware Version
    as::DeviceType::BlindActuator, // Device Type
    {0x01,0x00}                    // Info Bytes
};

/**
 * Configure the used hardware
 */
typedef AvrSPI<10,11,12,13> RadioSPI;
typedef AskSin<StatusLed<LED_PIN>,NoBattery,Radio<RadioSPI,2> > Hal;
//typedef AskSin<StatusLed<4>,NoBattery,NoRadio> Hal;

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

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;

  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 )
    {
      motorUp();
    }
    else if( newstate == AS_CM_JT_RAMPOFF && stateDelay > 0 )
    {
      motorDown();
    }
    else if(( newstate == AS_CM_JT_ON && stateDelay > 0 ) || ( newstate == AS_CM_JT_OFF && stateDelay > 0 ))
    {
      DPRINT("STOP newstate = ");
      DDECLN(newstate);
      motorStop();
    }
    else
    {
      DPRINT("newstate = ");
      DDECLN(newstate);
    }  
  }

  void motorUp ()
  {
    digitalWrite(UP_PIN,HIGH);    
    digitalWrite(DOWN_PIN,LOW);
    PulseReset.reset_pins(500);
  }
  
  void motorDown ()
  {

    digitalWrite(UP_PIN,LOW);
    digitalWrite(DOWN_PIN,HIGH);
    PulseReset.reset_pins(500);
  }

  void motorStop ()
  {
    digitalWrite(UP_PIN,HIGH);
    digitalWrite(DOWN_PIN,HIGH);
    PulseReset.reset_pins(500);
  }

  void init ()
  {
    PulseReset.init(UP_PIN, DOWN_PIN);    
    pinMode(UP_PIN,OUTPUT);
    pinMode(DOWN_PIN,OUTPUT);

    motorStop();
    BaseChannel::init();
  }
};

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

Hal hal;
BlindType sdev(devinfo,0x20);
ConfigButton<BlindType> cfgBtn(sdev);
// InternalButton<BlindType> btnup(sdev,1);
InternalButton<BlindType,LOW,HIGH,INPUT> btnup(sdev,1);
// InternalButton<BlindType> btndown(sdev,2);
InternalButton<BlindType,LOW,HIGH,INPUT> btndown(sdev,2);

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

void setup () {
  DINIT(57600,ASKSIN_PLUS_PLUS_IDENTIFIER);
  //storage().setByte(0,0);
  bool first = sdev.init(hal);
  sdev.channel(1).init();

//  sdev.channel(1).getList1().refRunningTimeBottomTop(270);
//  sdev.channel(1).getList1().refRunningTimeTopBottom(270);

  buttonISR(cfgBtn,CONFIG_BUTTON_PIN);
  buttonISR(btnup,UP_BUTTON_PIN);
  buttonISR(btndown,DOWN_BUTTON_PIN);

  initPeerings(first);
  sdev.initDone();
}

void loop() {
  bool worked = hal.runready();
  bool poll = sdev.pollRadio();
  if( worked == false && poll == false )
  {
    hal.activity.savePower<Idle<> >(hal);
  }
}
OutputPulseReset.h

Code: Alles auswählen

#ifndef __OUTPUT_PULSE_RESET_H__
#define __OUTPUT_PULSE_RESET_H__

#include <AlarmClock.h>

namespace as
{

  class OutputPulseReset : public Alarm
  {
  private:
    uint8_t pin_up;
    uint8_t pin_down;
  public:
    OutputPulseReset () : Alarm(0)
    {
      async(true);
    }
    virtual ~OutputPulseReset () {}

    virtual void trigger (AlarmClock& clock)
    {
      digitalWrite(pin_up,LOW);
      digitalWrite(pin_down,LOW);
    }

    void init (uint8_t p_up, uint8_t p_down)
    {
      pin_up = p_up;
      pin_down = p_down;
    }

    void reset_pins(uint16_t millis)
    {
      sysclock.cancel(*this);
      set(millis2ticks(millis));
      sysclock.add(*this);
    }
    
  };
}

#endif
Damit sind die Funktionen 0(nichts)/1(up kurz)/2(down kurz) implementiert und funktionieren, sowohl per Homematic Befehl als auch per IB-Bus Button.

Was mir jetzt fehlt, sind folgende Möglichkeiten:
1) Unterscheidung, ob ein Button lang oder kurz gedrückt wurde
2) Feststellen, ob beide Buttons gleichzeitig gedrückt wurden (IB: Stopp)
3) Anpassung der Homematic Bedienung: normale Fahrbefehle (Erzeugung kurzer Signale, schon vorhanden) und Notfall-Fahrbefehle (Erzeugung langer Signale)

Dazu benötige ich Unterstützung!

Oliver

Antworten

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