288 lines
13 KiB
C
288 lines
13 KiB
C
//#######################################################################################################
|
|
//## This Plugin is only for use with the RFLink software package ##
|
|
//## Plugin-006 Blyss & Avidsen ##
|
|
//#######################################################################################################
|
|
/*********************************************************************************************\
|
|
* This Plugin takes care of receiving of the Blyss protocol
|
|
*
|
|
* Author : StuntTeam
|
|
* Support : http://sourceforge.net/projects/rflink/
|
|
* License : This code is free for use in any open source project when this header is included.
|
|
* Usage of any parts of this code in a commercial application is prohibited!
|
|
*********************************************************************************************
|
|
* Changelog: v1.0 initial release
|
|
*********************************************************************************************
|
|
* Technical information:
|
|
* RF packets contain 106 pulses, 52 bits
|
|
*
|
|
* BLYSS Message Format:
|
|
* AAAAAAAA BBBBCCCC CCCCCCCC CCCCDDDD | EEEEFFFF FFFFGGGG GGGG
|
|
*
|
|
* A = Preamble, always 0xFE (0x32 in case of Avidsen)
|
|
* B = Global Channel (A=0,B=1,C=2,D=3)
|
|
* C = Address
|
|
* D = sub channel (channel 1=8, 2=4, 3=2, 4=1, 5=3) all channels = 0
|
|
* E = Light Status
|
|
* F = Rolling Code (0x98 -> 0xDA -> 0x1E -> 0xE6 -> 0x67)
|
|
* G = Time Stamp (random value?)
|
|
*
|
|
* Details https://skyduino.wordpress.com/2012/07/19/hack-partie-2-reverse-engineering-des-interrupteurs-domotique-blyss/
|
|
* https://barbudor.wiki.zoho.com/Système-domotique-Blyss-de-Castorama.html
|
|
*
|
|
* BlyssSend address,switch,cmd; => (16 bits,8 bits,on/off/allon/alloff)
|
|
* 20;0B;DEBUG;Pulses=106;Pulses(uSec)=2160,450,570,420,600,420,600,450,570,420,600,420,600,450,570,810,210,870,150,840,180,840,180,840,180,420,600,420,600,420,600,450,570,420,600,420,600,420,600,420,600,420,600,840,180,840,210,450,570,450,600,810,180,840,180,840,180,420,600,810,210,840,180,810,210,810,210,870,180,810,210,450,570,450,570,840,180,840,210,450,570,420,600,840,180,810,210,840,180,840,210,840,180,840,180,810,210,840,210,420,600,810,210,420,600,6990;
|
|
* 20;0C;Blyss;ID=ff98;SWITCH=A1;CMD=OFF;
|
|
\*********************************************************************************************/
|
|
#define BLYSS_PULSECOUNT 106
|
|
#define BLYSS_PULSEMID 500/RAWSIGNAL_SAMPLE_RATE
|
|
|
|
#ifdef PLUGIN_006
|
|
boolean Plugin_006(byte function, char *string) {
|
|
if (RawSignal.Number != BLYSS_PULSECOUNT) return false;
|
|
unsigned long bitstream=0L;
|
|
unsigned long bitstream1=0L;
|
|
byte bitcounter=0;
|
|
byte checksum=0;
|
|
int type=0;
|
|
//==================================================================================
|
|
// get bits
|
|
for(byte x=2;x < BLYSS_PULSECOUNT;x=x+2) {
|
|
if (RawSignal.Pulses[x] > BLYSS_PULSEMID) {
|
|
if (bitcounter < 32) {
|
|
bitstream = (bitstream << 1);
|
|
} else {
|
|
bitstream1 = (bitstream1 << 1);
|
|
}
|
|
bitcounter++;
|
|
} else {
|
|
if (bitcounter < 32) {
|
|
bitstream = (bitstream << 1) | 0x1;
|
|
} else {
|
|
bitstream1 = (bitstream1 << 1) | 0x1;
|
|
}
|
|
bitcounter++;
|
|
}
|
|
}
|
|
//==================================================================================
|
|
// all bits received, make sure checksum is okay
|
|
//==================================================================================
|
|
checksum=((bitstream) >> 24); // test preamble
|
|
if ((checksum != 0xFE) && (checksum != 0x32) ) return false; // must be 0xFE/32
|
|
if (checksum == 0x32) type=1;
|
|
//==================================================================================
|
|
// Prevent repeating signals from showing up
|
|
//==================================================================================
|
|
if(SignalHash!=SignalHashPrevious || RepeatingTimer<millis()) {
|
|
// not seen the RF packet recently
|
|
} else {
|
|
// already seen the RF packet recently
|
|
return true;
|
|
}
|
|
//==================================================================================
|
|
byte status=((bitstream1) >> 16) &0x0f;
|
|
if (status > 3) return false;
|
|
byte channel=((bitstream) >> 20) &0x0f;
|
|
unsigned int address=((bitstream) >> 4) &0xffff;
|
|
byte subchan=(bitstream) &0xf;
|
|
channel=channel+0x41;
|
|
if (subchan==8) {
|
|
subchan=1;
|
|
} else
|
|
if (subchan==4) {
|
|
subchan=2;
|
|
} else
|
|
if (subchan==2) {
|
|
subchan=3;
|
|
} else
|
|
if (subchan==1) {
|
|
subchan=4;
|
|
} else
|
|
if (subchan==3) {
|
|
subchan=5;
|
|
}
|
|
//==================================================================================
|
|
// Output
|
|
// ----------------------------------
|
|
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++);// Node and packet number
|
|
Serial.print( pbuffer );
|
|
// ----------------------------------
|
|
if (type == 0) {
|
|
Serial.print(F("Blyss;")); // Label
|
|
} else {
|
|
Serial.print(F("Avidsen;")); // Label
|
|
}
|
|
sprintf(pbuffer, "ID=%04x;", address); // ID
|
|
Serial.print( pbuffer );
|
|
sprintf(pbuffer, "SWITCH=%c%d;", channel,subchan);
|
|
Serial.print( pbuffer );
|
|
Serial.print(F("CMD=")); // command
|
|
if (status==0) Serial.print(F("ON;"));
|
|
if (status==1) Serial.print(F("OFF;"));
|
|
if (status==2) Serial.print(F("ALLON;"));
|
|
if (status==3) Serial.print(F("ALLOFF;"));
|
|
Serial.println();
|
|
//==================================================================================
|
|
RawSignal.Repeats=true; // suppress repeats of the same RF packet
|
|
RawSignal.Number=0;
|
|
return true;
|
|
}
|
|
#endif // PLUGIN_006
|
|
|
|
#ifdef PLUGIN_TX_006
|
|
void Blyss_Send(unsigned long address, byte devtype);
|
|
|
|
boolean PluginTX_006(byte function, char *string) {
|
|
boolean success=false;
|
|
//10;Avidsen;00ff98;A1;OFF;
|
|
//012345678901234567890123456
|
|
//10;Blyss;00ff98;A1;OFF;
|
|
//012345678901234567890123456
|
|
int offset=0;
|
|
if (strncasecmp(InputBuffer_Serial+3,"AVIDSEN;",8) == 0) { // Blyss Command eg.
|
|
offset=2;
|
|
}
|
|
if ((strncasecmp(InputBuffer_Serial+3,"BLYSS;",6) == 0) || (offset==2)) { // Blyss Command eg.
|
|
unsigned long Bitstream = 0L;
|
|
if (InputBuffer_Serial[15+offset] != ';') return success; // check
|
|
if (InputBuffer_Serial[18+offset] != ';') return success; // check
|
|
|
|
unsigned long Home=0; // Blyss channel A..P
|
|
byte Address=0; // Blyss subchannel 1..5
|
|
byte c;
|
|
byte subchan=0; // subchannel
|
|
|
|
InputBuffer_Serial[7+offset]=0x30;
|
|
InputBuffer_Serial[8+offset]=0x78;
|
|
InputBuffer_Serial[15+offset]=0;
|
|
Bitstream=str2int(InputBuffer_Serial+7+offset); // get address
|
|
|
|
c=tolower(InputBuffer_Serial[16+offset]); // A..P
|
|
if(c>='a' && c<='p'){Home=c-'a';}
|
|
c=tolower(InputBuffer_Serial[17+offset]); // 1..5
|
|
if(c>='1' && c<='5'){Address=Address+c-'0';}
|
|
|
|
if (Address==1) subchan=0x80;
|
|
if (Address==2) subchan=0x40;
|
|
if (Address==3) subchan=0x20;
|
|
if (Address==4) subchan=0x10;
|
|
if (Address==5) subchan=0x30;
|
|
|
|
Home = Home << 24;
|
|
Bitstream=(Bitstream) << 8;
|
|
Bitstream=Bitstream+subchan;
|
|
Bitstream=Bitstream+Home;
|
|
|
|
c = str2cmd(InputBuffer_Serial+19+offset); // ALL ON/OFF command
|
|
if (c == VALUE_OFF) {
|
|
Bitstream=Bitstream|1;
|
|
} else {
|
|
if (c == VALUE_ALLOFF) {
|
|
Bitstream=Bitstream|3;
|
|
} else
|
|
if (c == VALUE_ALLON) {
|
|
Bitstream=Bitstream|2;
|
|
}
|
|
}
|
|
Blyss_Send(Bitstream, offset); // Bitstream contains the middle part of the bitstream to send
|
|
success=true;
|
|
}
|
|
return success;
|
|
}
|
|
|
|
void Blyss_Send(unsigned long address, byte devtype) {
|
|
int fpulse = 400; // Pulse witdh in microseconds
|
|
int fretrans = 8; // Number of code retransmissions
|
|
uint32_t fdatabit;
|
|
uint32_t fdatamask = 0x800000;
|
|
uint32_t fsendbuff;
|
|
unsigned char RollingCode[] = { 0x98, 0xDA, 0x1E, 0xE6, 0x67, 0x98};
|
|
|
|
digitalWrite(PIN_RF_RX_VCC,LOW); // Power off the RF receiver
|
|
digitalWrite(PIN_RF_TX_VCC,HIGH); // Turn on the RF transmitter
|
|
delayMicroseconds(TRANSMITTER_STABLE_DELAY); // short delay to let the transmitter become stable (Note: Aurel RTX MID needs 500µS/0,5ms)
|
|
byte temp=(millis() &0xff); // used for the timestamp at the end of the RF packet
|
|
for (int nRepeat = 0; nRepeat <= fretrans; nRepeat++) {
|
|
// send SYNC 1P low, 6P high
|
|
digitalWrite(PIN_RF_TX_DATA, LOW);
|
|
delayMicroseconds(fpulse);
|
|
digitalWrite(PIN_RF_TX_DATA, HIGH);
|
|
delayMicroseconds(fpulse * 6);
|
|
// end send SYNC
|
|
// --------------
|
|
// Send preamble (0xfe) - 8 bits
|
|
if (devtype == 0) {
|
|
fsendbuff=0x32;
|
|
} else {
|
|
fsendbuff=0xfe;
|
|
}
|
|
fdatamask=0x80;
|
|
for (int i = 0; i < 8; i++) { // Preamble
|
|
// read data bit
|
|
fdatabit = fsendbuff & fdatamask; // Get most left bit
|
|
fsendbuff = (fsendbuff << 1); // Shift left
|
|
if (fdatabit != fdatamask) { // Write 0
|
|
digitalWrite(PIN_RF_TX_DATA, LOW);
|
|
delayMicroseconds(fpulse * 2);
|
|
digitalWrite(PIN_RF_TX_DATA, HIGH);
|
|
delayMicroseconds(fpulse * 1);
|
|
} else { // Write 1
|
|
digitalWrite(PIN_RF_TX_DATA, LOW);
|
|
delayMicroseconds(fpulse * 1);
|
|
digitalWrite(PIN_RF_TX_DATA, HIGH);
|
|
delayMicroseconds(fpulse * 2);
|
|
}
|
|
}
|
|
// --------------
|
|
fsendbuff=address;
|
|
fdatamask=0x8000000;
|
|
// Send command (channel/address/status) - 28 bits
|
|
for (int i = 0; i < 28; i++) {
|
|
// read data bit
|
|
fdatabit = fsendbuff & fdatamask; // Get most left bit
|
|
fsendbuff = (fsendbuff << 1); // Shift left
|
|
if (fdatabit != fdatamask) { // Write 0
|
|
digitalWrite(PIN_RF_TX_DATA, LOW);
|
|
delayMicroseconds(fpulse * 2);
|
|
digitalWrite(PIN_RF_TX_DATA, HIGH);
|
|
delayMicroseconds(fpulse * 1);
|
|
} else { // Write 1
|
|
digitalWrite(PIN_RF_TX_DATA, LOW);
|
|
delayMicroseconds(fpulse * 1);
|
|
digitalWrite(PIN_RF_TX_DATA, HIGH);
|
|
delayMicroseconds(fpulse * 2);
|
|
}
|
|
}
|
|
// --------------
|
|
// Send rolling code & timestamp - 16 bits
|
|
fsendbuff=RollingCode[nRepeat];
|
|
fsendbuff=(fsendbuff<<8)+temp;
|
|
//fsendbuff=0x9800 + temp;
|
|
fdatamask=0x8000;
|
|
for (int i = 0; i < 16; i++) {
|
|
// read data bit
|
|
fdatabit = fsendbuff & fdatamask; // Get most left bit
|
|
fsendbuff = (fsendbuff << 1); // Shift left
|
|
if (fdatabit != fdatamask) { // Write 0
|
|
digitalWrite(PIN_RF_TX_DATA, LOW);
|
|
delayMicroseconds(fpulse * 2);
|
|
digitalWrite(PIN_RF_TX_DATA, HIGH);
|
|
delayMicroseconds(fpulse * 1);
|
|
} else { // Write 1
|
|
digitalWrite(PIN_RF_TX_DATA, LOW);
|
|
delayMicroseconds(fpulse * 1);
|
|
digitalWrite(PIN_RF_TX_DATA, HIGH);
|
|
delayMicroseconds(fpulse * 2);
|
|
}
|
|
}
|
|
// --------------
|
|
digitalWrite(PIN_RF_TX_DATA, LOW);
|
|
//delayMicroseconds(fpulse * 18); // delay between RF retransmits
|
|
delay(24); // delay 23.8 ms
|
|
}
|
|
delayMicroseconds(TRANSMITTER_STABLE_DELAY); // short delay to let the transmitter become stable (Note: Aurel RTX MID needs 500µS/0,5ms)
|
|
digitalWrite(PIN_RF_TX_VCC,LOW); // turn off the RF transmitter
|
|
digitalWrite(PIN_RF_RX_VCC,HIGH); // power on the RF receiver
|
|
RFLinkHW();
|
|
}
|
|
#endif // PLUGIN_TX_006
|