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:
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);
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 )
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);
}
}
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
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