feature-requests
feature-requests copied to clipboard
Wiegand interface
Describe the problem you have/What new integration you would like I am using wiegand access. It would be nice to be able to integrate this kind of equipment to ESPHome
Please describe your use case for this integration and alternatives you've tried: At the moment, I am using a home made script. Having one solution for all would be nice.
Additional context
I think the RDM6300 uses wiegand - could you try with the rdm6300 integration?
The RDM6300 seems to use a standard UART protocol. Wiegand is its own beast. It would require some interrupt-driven communication for accuracy, but does seem fairly simple.
There's a good library that can figure out the number of bits in the data automagically. If I had time, I'd port it. Any takers?
https://github.com/paulo-raca/YetAnotherArduinoWiegandLibrary
That would be very good. I have a weigand reader outside, knowing the tag read would be perfect for integrating it into Home Assistant. Not knowing the tag I have mapped the relay as an ON/OFF, and I will have to put another rfid reader integrated for automations since I want some automation just for my tag and my girlfriend's, not for other tags.
I have a couple of Siemens AR6182-MX readers (w/keypads) that can be configure to use a Wiegand interface, would be interesting to get this hooked up to EspHome.
Tried the YetAnotherArduinoWiegandLibrary and it works on arduino but not ESP8266. Found https://github.com/esprfid/esp-rfid which uses https://github.com/monkeyboard/Wiegand-Protocol-Library-for-Arduino.git but this didn't boot on my NodeMCU board at all. Might poke more later, but in case the links are of interest ☝️
This fixes the library used in esp-rfid as linked to above https://github.com/monkeyboard/Wiegand-Protocol-Library-for-Arduino/pull/38
Unfortunately I need other bitcounts than standard depending on card type and optional pin length so I'll probably do a AR6182-MX library instead of a generic Wiegand.
@beikeland I am using esp-rfid project on my nodeMCU since a couple of weeks, just use version 1.0.2 since latest one has problems with MQTT messages for tags.
My primary motivation for looking into using ESPhome was to not rely on MQTT. I've got the library working and sorted out separating Pin, Card and Card+Pin in an Arduino sketch running on a NodeMCU-devkit. So just have to wrap my head around the abstraction needed to write a new component for the Wiegand bus and a sensor or something on top of that, or find that someone beats me to it while trying to understand the ESPhome code:)
I understand that, I just replied to the fact that it wasn't booting on your nodeMCU ;)
That was due to the missing ICACHE attribute for the interrupt handler in the underlying library. Fixed it.
On Thu, Jul 18, 2019 at 1:34 PM nerdosity [email protected] wrote:
I understand that, I just replied to the fact that it wasn't booting on your nodeMCU ;)
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/esphome/feature-requests/issues/211?email_source=notifications&email_token=AAUTS3RPMROPNEK6IKZNRDLQABINZA5CNFSM4HKTC32KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD2IGHOQ#issuecomment-512779194, or mute the thread https://github.com/notifications/unsubscribe-auth/AAUTS3URDCHZMNLVY22GOADQABINZANCNFSM4HKTC32A .
Still trying to work out how to add the components to ESPHome, maybe one day. Sharing a gist with the working arduino sketch for esp8266 and AR6182 reader. Reader uses an electric wiegand interface, but custom protocol. https://gist.github.com/beikeland/145b20b1fc585049ea8951eddfc5732e
I have a bunch of HID Prox readers, would love a component to use them with ESPHome! Currently using them with https://github.com/TomHarkness/homeID
Any news on that? I've bought a keypad that use this protocol and would like to wiring it to an ESP32 running ESPHOME
Also interested in using wiegand keypads connected to an ESP8266/ESP32.
Can you help me building the plugin ?
I’d be happy to give it a go, but I’m not much of a programmer these days. More of a scripter I’d say.
While I’m thinking about it, one feature I’d like to see is the ability to set codes/card numbers in HomeAssistant (or whatever frontend) and have them cached locally on the ESP.
You must need the card number to be passed to home assistant, then you can do what you want with it.
On Sun, 12 Jan 2020, 12:49 am Caleb Edwards, [email protected] wrote:
I’d be happy to give it a go, but I’m not much of a programmer these days. More of a scripter I’d say.
While I’m thinking about it, one feature I’d like to see is the ability to set codes/card numbers in HomeAssistant (or whatever frontend) and have them cached locally on the ESP.
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/esphome/feature-requests/issues/211?email_source=notifications&email_token=ABP5BVHK2LB73ZEJCCAAB2DQ5HE53A5CNFSM4HKTC32KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEIWCK5A#issuecomment-573318516, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABP5BVCRMOCRY5SU5SE65U3Q5HE53ANCNFSM4HKTC32A .
If you want local cache / standalone control, you might want to look at the esprfid project. It can also talk to Mqtt so can also be manually integrated with stuff like Hass.
https://github.com/esprfid/esp-rfid
You don't need their special board, any esp8266 will do. I used it to handle card reading/users and had Hass control the lock. Worked quite well.
Still would be good to have weigand in esphome, to keep everything on one platform.
Sent from Ninehttp://www.9folders.com/
From: Caleb Edwards [email protected] Sent: Saturday, January 11, 2020 8:49 AM To: esphome/feature-requests Cc: Wade J. Weppler; Comment Subject: Re: [esphome/feature-requests] Wiegand interface (#211)
I’d be happy to give it a go, but I’m not much of a programmer these days. More of a scripter I’d say.
While I’m thinking about it, one feature I’d like to see is the ability to set codes/card numbers in HomeAssistant (or whatever frontend) and have them cached locally on the ESP.
— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/esphome/feature-requests/issues/211?email_source=notifications&email_token=AAGOH54GIWWMK5GXAEOSI53Q5HE53A5CNFSM4HKTC32KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEIWCK5A#issuecomment-573318516, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAGOH5Y4SLFAYOZPNN365CDQ5HE53ANCNFSM4HKTC32A.
I'm not interest of just RFID. I would like the complete wiegand protocol. Either Keypad of RDIF will be pass to HA.
And like @edwardscaleb9 said, it would be great to program the keypas via HA.
I've found online a library for Weigand, but dont have the skills to implement it with ESPHOME.
Someone with those skill would want to help us ?
I was able to implement a CustomAPIDevice using code from this Github repo without any issues. The code works as is (I had to drop the IRAM_ATTR
on the interrupt handlers in order to get it to link but it's working well for me.
I can post the sample custom device code if anyone is interested.
@gdoerr i’m really interested to see how you did it !!
Save the code below as wiegand_device.h and include it as a custom component in your YAML file.
custom_component:
- lambda: |-
auto wiegand = new WiegandReader(pin0, pin1, "script.to_call");
return {wiegand};
pin0
should be the GPIO connected to the D0 signal and pin1
is the GPIO connected to the D1 signal. Replace "script.to_call"
with the name of the script or service to call. The code entered will be passed as the parameter code
.
#include "esphome.h"
/**
* Wiegand Reader Custom Device
*
* Copied from https://github.com/monkeyboard/Wiegand-Protocol-Library-for-Arduino
* Implemented by Greg Doerr (https://github.com/gdoerr)
*
* In my example, hooked to an Olimex ESP32-POE device connected to a Retekess H1EM-W
* Wiegand keypad. This device calls a service on Home Assistant when a code is available
*
* Samples key presses every 200ms and stores the key in a string until:
* [1] - the user presses a '#' which sends the code immediately
* [2] - the user presses nothing for 2,000ms (inter-digit timer) which then sends the code
* [3] - the user presses a '*' which sends the '*' immediately
*/
class WiegandReader : public PollingComponent, public CustomAPIDevice {
public:
WiegandReader(int pinD0, int pinD1, std::string serviceName)
: PollingComponent(200),
pinD0(pinD0), pinD1(pinD1),
serviceName(serviceName) {
}
/**
* Initial setup
*/
void setup() override {
_lastWiegand = 0;
_cardTempHigh = 0;
_cardTemp = 0;
_code = 0;
_wiegandType = 0;
_bitCount = 0;
// Configure the input pins
pinMode(pinD0, INPUT);
pinMode(pinD1, INPUT);
// Attach the interrupts
attachInterrupt(digitalPinToInterrupt(pinD0), ReadD0, FALLING); // Hardware interrupt - high to low pulse
attachInterrupt(digitalPinToInterrupt(pinD1), ReadD1, FALLING); // Hardware interrupt - high to low pulse
}
void update() override {
// See if we have a valid code
noInterrupts();
bool rc = DoWiegandConversion();
interrupts();
if(rc) {
if(_code < 10) {
// We have a digit, make it ASCII for convenience
keyCodes += (_code + 0x30);
} else if(_code == 11) {
// The user pressed '#', send the accumulated code and reset for the next string
callHAService(keyCodes);
keyCodes = "";
} else if(_code == 10) {
// The user pressed '*', clear the code and send the asterisk
callHAService("*");
keyCodes = "";
}
// Capture the last time we received a code
lastCode = millis();
} else {
if(keyCodes.length() > 0) {
// We have a keyCode, see if the interdigit timer expired
if(millis() - lastCode > 2000) {
// The interdigit timer expired, send the code and reset for the next string
callHAService(keyCodes);
keyCodes = "";
}
}
}
}
private:
static volatile unsigned long _cardTempHigh;
static volatile unsigned long _cardTemp;
static volatile unsigned long _lastWiegand;
static volatile int _bitCount;
static int _wiegandType;
static unsigned long _code;
unsigned long lastCode = 0;
std::string keyCodes = "";
int pinD0;
int pinD1;
std::string serviceName;
/**
* Calls a Home Assistant service with the key code
* @param keyCode
*/
void callHAService(std::string keyCode) {
call_homeassistant_service(serviceName.c_str(), {
{"code", keyCode.c_str()}
});
}
/**
* D0 Interrupt Handler
*/
static void ReadD0() {
_bitCount++; // Increment bit count for Interrupt connected to D0
if(_bitCount > 31) { // If bit count more than 31, process high bits
_cardTempHigh |= ((0x80000000 & _cardTemp)>>31); // shift value to high bits
_cardTempHigh <<= 1;
_cardTemp <<=1;
} else
_cardTemp <<= 1; // D0 represent binary 0, so just left shift card data
_lastWiegand = millis(); // Keep track of last wiegand bit received
}
/**
* D1 Interrupt Handler
*/
static void ReadD1() {
_bitCount ++; // Increment bit count for Interrupt connected to D1
if(_bitCount > 31) { // If bit count more than 31, process high bits
_cardTempHigh |= ((0x80000000 & _cardTemp)>>31); // shift value to high bits
_cardTempHigh <<= 1;
_cardTemp |= 1;
_cardTemp <<=1;
} else {
_cardTemp |= 1; // D1 represent binary 1, so OR card data with 1 then
_cardTemp <<= 1; // left shift card data
}
_lastWiegand = millis(); // Keep track of last wiegand bit received
}
/**
* Extract the Card ID from the received bit stream
* @param codehigh
* @param codelow
* @param bitlength
* @return
*/
unsigned long getCardId(volatile unsigned long *codehigh, volatile unsigned long *codelow, char bitlength) {
if (bitlength==26) // EM tag
return (*codelow & 0x1FFFFFE) >>1;
if (bitlength==34) // Mifare
{
*codehigh = *codehigh & 0x03; // only need the 2 LSB of the codehigh
*codehigh <<= 30; // shift 2 LSB to MSB
*codelow >>=1;
return *codehigh | *codelow;
}
return *codelow; // EM tag or Mifare without parity bits
}
/**
* Convert the received bitstream
* @return
*/
bool DoWiegandConversion () {
unsigned long cardID;
unsigned long sysTick = millis();
if ((sysTick - _lastWiegand) > 25) // if no more signal coming through after 25ms
{
if ((_bitCount==24) || (_bitCount==26) || (_bitCount==32) || (_bitCount==34) || (_bitCount==8) || (_bitCount==4)) { // bitCount for keypress=4 or 8, Wiegand 26=24 or 26, Wiegand 34=32 or 34
_cardTemp >>= 1; // shift right 1 bit to get back the real value - interrupt done 1 left shift in advance
if (_bitCount>32) // bit count more than 32 bits, shift high bits right to make adjustment
_cardTempHigh >>= 1;
if (_bitCount==8) { // keypress wiegand with integrity
// 8-bit Wiegand keyboard data, high nibble is the "NOT" of low nibble
// eg if key 1 pressed, data=E1 in binary 11100001 , high nibble=1110 , low nibble = 0001
char highNibble = (_cardTemp & 0xf0) >>4;
char lowNibble = (_cardTemp & 0x0f);
_wiegandType=_bitCount;
_bitCount=0;
_cardTemp=0;
_cardTempHigh=0;
if (lowNibble == (~highNibble & 0x0f)) { // check if low nibble matches the "NOT" of high nibble.
_code = (int)lowNibble;
return true;
} else {
_lastWiegand=sysTick;
_bitCount=0;
_cardTemp=0;
_cardTempHigh=0;
return false;
}
// TODO: Handle validation failure case!
} else if (4 == _bitCount) {
// 4-bit Wiegand codes have no data integrity check so we just
// read the LOW nibble.
_code = (int)(_cardTemp & 0x0000000F);
_wiegandType = _bitCount;
_bitCount = 0;
_cardTemp = 0;
_cardTempHigh = 0;
return true;
} else { // wiegand 26 or wiegand 34
cardID = getCardId (&_cardTempHigh, &_cardTemp, _bitCount);
_wiegandType=_bitCount;
_bitCount=0;
_cardTemp=0;
_cardTempHigh=0;
_code=cardID;
return true;
}
} else {
// well time over 25 ms and bitCount !=8 , !=26, !=34 , must be noise or nothing then.
_lastWiegand=sysTick;
_bitCount=0;
_cardTemp=0;
_cardTempHigh=0;
return false;
}
} else
return false;
}
};
volatile unsigned long WiegandReader::_cardTempHigh = 0;
volatile unsigned long WiegandReader::_cardTemp = 0;
volatile unsigned long WiegandReader::_lastWiegand = 0;
volatile int WiegandReader::_bitCount = 0;
unsigned long WiegandReader::_code = 0;
int WiegandReader::_wiegandType = 0;
Wow @gdoerr , that's a greate job you did! Thanks ! Since i'm pretty new to this, and i've buy the exact same keypad as you, can you help me with something more. I'll like to push the data into a text_sensor: can you explain me what I have to that to the yaml and .h file?
Thanks again!
And i'm using a ESP-32 for now, can I use any GPIO pin ?
You'd have to restructure the Wiegand class into a TextSensor. I don't recommend this because you're not interested in state, you really want the event which is why I call a service. You should be able to find the example code on esphome to implement a custom text sensor.
You should be able to use any GPIO pins on the ESP32 but the order is important...swap D0 and D1 if your're getting weird results.
Good Luck!
What would you recommend to write in the script to call to received as a event ?
You can use either a yaml script or a python script.
I use a python script to validate the code sequences against a dedicated outlook.com calendar to control access to my garage.
Or maybe only share your how implentation, that's help me reverse engineering and understand or to implement it for my use.
I've tried to change the class declaration from CustomApiDevice to TextSensor and add PublishState(keyCode) to CallHaService without success
@pricard32 Rather than mucking up this feature request thread with a specific problem, perhaps you can post your question on Stack Overflow which is better suited and then post a link to the problem here.
I'm happy to help but you'll need to provide more information than you tried something without success. When you ask the question, be sure and post exactly what you tried and what errors you're getting. Otherwise it's difficult to help you without writing the software for you...
@gdoerr great work! Solves the immediate problem and really helped me understand how custom components work in esphome. Well done, and thank you.