Hi all!
I got stucked with my first custom integration.
I want to integrate a rfid reader.
I have use the code from gdoerr
The code has been successfully read with my rfid reader and printed in the ESPhome logger
Now I have two choices. 1. I can publish the code to my “controlAccess” topic which has a script to check the access permission of the code. But my problem is I need 3 variables to complete the logic proccess:
payload= {
‘id’: ‘door’,
‘code’: wiegand_code,
‘timeStamp’: now()
}
and I dont know if would be possible to build in my esphome.yalm this structure and publish the json directly from the device in to the topic.
2. I could call a script which process the code and build the complete payload.
My problem is that the the script is not tiggered with this config and I dont know why.
My ESPhome yaml is:
custom_component:
- lambda: |-
auto wiegand = new WiegandReader(21, 23, "python_scripts.door_mqtt_publish.py");
return {wiegand};
in config/python_scripts/door_publish_mqtt.py I have a simple code just to test it
logger.info("PYTHON SCRIPT CALLED")
name = data.get('code')
logger.info("HELLOOOOOOOOO %s", name)
hass.bus.fire(name, {"test": "from a Python script!"}
)
and I think that services is not mandatory, anaway: config/python_scripts/services.yaml
door_mqtt_publish:
description: publish a rfid code
field:
code:
description: code format
example: 9451293
In the ESP home logger I can see that the code is read perfectly but I can not trigger the python script to send the payload with the code on it. After read a code nothing appears in the HA logger.
HA logger:
2020-02-03 12:25:05 WARNING (MainThread) [homeassistant.loader] You are using a custom integration for hacs which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you do experience issues with Home Assistant.
2020-02-03 12:25:05 WARNING (MainThread) [homeassistant.loader] You are using a custom integration for customizer which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you do experience issues with Home Assistant.
2020-02-03 12:25:36 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection.1908784496] Error handling message: Unauthorized
I have wrote the code and I will check tomorrow to fix the mistakes.
The only thing that I dind´t undertand is how can I add the timeStamp using the api time from esphome.h to my payload setup
#include "esphome.h"
/**
* Wiegand Reader Custom Device
*
* Inspired in https://github.com/monkeyboard/Wiegand-Protocol-Library-for-Arduino
* and https://github.com/esphome/feature-requests/issues/211
*/
class WiegandReader : public PollingComponent, public CustomMQTTDevice {
public:
WiegandReader(int pinD0, int pinD1)
: PollingComponent(200),
pinD0(pinD0), pinD1(pinD1)
/**
* Initial setup
*/
void setup() override {
_lastWiegand = 0;
_cardTempHigh = 0;
_cardTemp = 0;
_code = 0;
_wiegandType = 0;
_bitCount = 0;
subscribe("the/topic", &WiegandReader::on_message);
// 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) {
// 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
json_message(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 lo queremos cambiar por enviar un json
void callHAService(std::string keyCode) {
call_homeassistant_service(serviceName.c_str(), {
{"code", keyCode.c_str()}
});
}
*/
void json_message(std::string keyCode) {
// publish JSON using lambda syntax
publish_json("the/other/json/topic", [=](JsonObject &root2) {
root2["door"] = 1
root2["code"] = keyCode.c_str();
root2["timeStamp"] = "blabla"
});
}
/**
* 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
// 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;
Did you solve your issue? I’m looking to integrate my Wiegand Keypad to HA too.
I’m not a big fan of MQTT but i could do it with this for this project…
@Stepan Sorry to be a bug, Just curious if you might have posted your code to GitHub?
I am trying to get custom UART and MQTT functioning, and would appreciate your code as a reference to get an old Matrix amp a new life
I’ve got errors when compiling your custom component…
In file included from src/main.cpp:15:0:
src/wiegand_device.h: In member function 'void WiegandReader::json_message(std::string)':
src/wiegand_device.h:89:13: error: 'RealTimeClock' was not declared in this scope
RealTimeClock *x = new RealTimeClock();
^
src/wiegand_device.h:89:28: error: 'x' was not declared in this scope
RealTimeClock *x = new RealTimeClock();
^
src/wiegand_device.h:89:36: error: expected type-specifier before 'RealTimeClock'
RealTimeClock *x = new RealTimeClock();
^
src/wiegand_device.h:89:36: error: expected ';' before 'RealTimeClock'
src/wiegand_device.h:90:13: error: 'ESPTime' was not declared in this scope
ESPTime time = x->utcnow();
^
src/wiegand_device.h:90:21: error: expected ';' before 'time'
ESPTime time = x->utcnow();
^
src/wiegand_device.h:92:18: error: request for member 'strftime' in 'time', which is of non-class type 'time_t(time_t*) {aka long int(long int*)}'
time.strftime(time2, 20, "%Y-%m-%d %H:%M:%S");
^
src/wiegand_device.h: In member function 'void WiegandReader::json_message2(long unsigned int)':
src/wiegand_device.h:102:13: error: 'RealTimeClock' was not declared in this scope
RealTimeClock *x = new RealTimeClock();
^
src/wiegand_device.h:102:28: error: 'x' was not declared in this scope
RealTimeClock *x = new RealTimeClock();
^
src/wiegand_device.h:102:36: error: expected type-specifier before 'RealTimeClock'
RealTimeClock *x = new RealTimeClock();
^
src/wiegand_device.h:102:36: error: expected ';' before 'RealTimeClock'
src/wiegand_device.h:103:13: error: 'ESPTime' was not declared in this scope
ESPTime time = x->utcnow();
^
src/wiegand_device.h:103:21: error: expected ';' before 'time'
ESPTime time = x->utcnow();
^
src/wiegand_device.h:105:18: error: request for member 'strftime' in 'time', which is of non-class type 'time_t(time_t*) {aka long int(long int*)}'
time.strftime(time2, 20, "%Y-%m-%d %H:%M:%S");
^
*** [/data/wemos_d1_wiegand/.pioenvs/wemos_d1_wiegand/src/main.cpp.o] Error 1
========================= [FAILED] Took 13.84 seconds =========================
I updated the code with the instructions.
The error is because you are missing this part in the .yaml because I forgot to added.
time: #- platform: homeassistant
I placed wiegand_device.H in /config/esphome/ and it works. Is it not right?
How work this component? When tag is recognised an mqtt with code is sent to HA, right?
Yes in this folder also work but if you have more than one door should be in src.
This component just publish a code in a topic, then you should create a automation which should check if the code exist in your list of know codes, then I check the timeStamp because a code can arrive with delay and open the door in a conflictive moment of time.
To create this component you can generate a Script, you can also implement it in nodered or others methods. Maybe I have a old code in nodered that can inspired you but I can´t share my actual setup because it is a specific case of use.
If you have just a few keys maybe you can simplify the flux doing the comprobation in the sensor and the sensor can send the message (“open the door”) directly to the actuator.
For security you should have both (actuator and sensor) separately because the sensor normaly its outdoor so accesible.
Ok, thank you. I already have an actuator inside my house and managed in HA. I think i will use an automation to parse the readed code with a list and if it pass drive the actuator (actually i drive it using rest commands from my phone with an app that read an nfc tag, see my signature). Do you use an automation in HA actually to manage readed codes?
Ok, can you show me how appear the complete mqtt message sent by the reader? I don’t use autodiscovery in ha, so i’m not sure how to setup mqtt sensor to retrieve the code…
The message is JSON format and you can check it easily in developer tools, in mqtt part and then subscribe to your topic.
{
“doorId”: 2,
“code”: 9999999,
“timeStamp”: “xx-yy-zz 00:00:00”
}