Compare commits
5 Commits
8198d8f62e
...
3ef68a9539
| Author | SHA1 | Date | |
|---|---|---|---|
|
3ef68a9539
|
|||
|
31861e7785
|
|||
|
b8581dcf31
|
|||
|
2809b1a167
|
|||
|
d3f0520123
|
@@ -0,0 +1,42 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.components import uart
|
||||
from esphome.const import (
|
||||
CONF_ID
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@nbsgames"]
|
||||
DEPENDENCIES=["uart"]
|
||||
|
||||
hoermann_door_ns = cg.esphome_ns.namespace('hoermann_door')
|
||||
HoermannDoor = hoermann_door_ns.class_('HoermannMainComponent', cg.Component)
|
||||
|
||||
CONF_UART_ENTRY = "uart_connection"
|
||||
CONF_TX_PIN = "tx_pin"
|
||||
|
||||
def validate_config(config):
|
||||
return config
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.COMPONENT_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_id(HoermannDoor),
|
||||
cv.Required(CONF_UART_ENTRY): cv.use_id(uart.UARTComponent),
|
||||
cv.Required(CONF_TX_PIN): pins.internal_gpio_output_pin_schema,
|
||||
}),
|
||||
validate_config
|
||||
)
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
#yield mqtt.register_mqtt_component(var, config)
|
||||
|
||||
#btnReset = yield cg.gpio_pin_expression(config[CONF_SENSOR_PIN])
|
||||
#cg.add(var.set_input_pin(btnReset))
|
||||
|
||||
code = await cg.get_variable(config[CONF_UART_ENTRY])
|
||||
cg.add(var.set_seriel_connection(code))
|
||||
|
||||
code2 = await cg.gpio_pin_expression(config[CONF_TX_PIN])
|
||||
cg.add(var.set_tx_on_pin(code2)) # Needs be configured before sensor
|
||||
@@ -3,18 +3,23 @@ import esphome.config_validation as cv
|
||||
from esphome import automation
|
||||
from esphome.components import cover
|
||||
from esphome.const import CONF_ID
|
||||
from . import HoermannDoor
|
||||
|
||||
hoermann_cover_ns = cg.esphome_ns.namespace('hoermann_door')
|
||||
HoermannDoor = hoermann_cover_ns.class_('HoermanDoor', cover.Cover, cg.Component)
|
||||
HoermannCover = hoermann_cover_ns.class_('HoermannDoor', cover.Cover, cg.Component)
|
||||
|
||||
CONFIG_SCHEMA = cover.COVER_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_id(HoermannDoor)
|
||||
}).extend(cv.COMPONENT_SCHEMA)
|
||||
CONF_HOERMANN_CONTROLLER = "hoermann_controller"
|
||||
|
||||
CONFIG_SCHEMA = cover.cover_schema(HoermannCover).extend({
|
||||
cv.Required(CONF_HOERMANN_CONTROLLER): cv.use_id(HoermannDoor)
|
||||
})
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield cover.register_cover(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await cover.register_cover(var, config)
|
||||
|
||||
controller = await cg.get_variable(config[CONF_HOERMANN_CONTROLLER])
|
||||
cg.add(var.set_emulator_component(controller))
|
||||
|
||||
cg.add_library("plerup/EspSoftwareSerial", "8.2.0")
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "door_singleton.h"
|
||||
|
||||
#ifdef USE_COVER
|
||||
|
||||
class HoermannDoorx;
|
||||
|
||||
#include "esphome.h"
|
||||
#include "Arduino.h"
|
||||
#include "hoermann.h"
|
||||
#include "hciemulator.h"
|
||||
//#include "cover.h"
|
||||
|
||||
@@ -13,14 +13,13 @@
|
||||
#define TX_ON 25
|
||||
//#define configMAX_PRIORITIES 25
|
||||
|
||||
#define TAG "hoermann_door"
|
||||
|
||||
namespace esphome {
|
||||
namespace hoermann_door {
|
||||
|
||||
void modBusPolling(void *parameter);
|
||||
class HoermanDoor : public Component, public cover::Cover
|
||||
class HoermannDoor : public Component, public cover::Cover
|
||||
{
|
||||
private:
|
||||
HoermannMainComponent* mainComponent;
|
||||
public:
|
||||
|
||||
cover::CoverTraits get_traits() override {
|
||||
@@ -48,11 +47,11 @@ public:
|
||||
|
||||
|
||||
if(pos == 1.0){
|
||||
HoermannSingleton::getInstance()->getEmulator()->openDoor();
|
||||
mainComponent->getEmulator()->openDoor();
|
||||
manual = false;
|
||||
}
|
||||
else if(pos == 0.0){
|
||||
HoermannSingleton::getInstance()->getEmulator()->closeDoor();
|
||||
mainComponent->getEmulator()->closeDoor();
|
||||
manual = false;
|
||||
}
|
||||
else{
|
||||
@@ -61,38 +60,21 @@ public:
|
||||
|
||||
}
|
||||
if (call.get_stop()) {
|
||||
HoermannSingleton::getInstance()->getEmulator()->stopDoor();
|
||||
mainComponent->getEmulator()->stopDoor();
|
||||
}
|
||||
//if(call.get_close()) {
|
||||
//emulator.closeDoor();
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void modBusPolling(void *parameter)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (lastCall > 0)
|
||||
{
|
||||
maxPeriod = _max(micros() - lastCall, maxPeriod);
|
||||
}
|
||||
lastCall = micros();
|
||||
emulator.poll();
|
||||
vTaskDelay(1);
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
*/
|
||||
|
||||
void setup() override
|
||||
{
|
||||
HoermannSingleton::getInstance()->initializeEmulator();
|
||||
//HoermannSingleton::getInstance()->initializeEmulator();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void set_emulator_component(HoermannMainComponent* component){
|
||||
this->mainComponent = component;
|
||||
}
|
||||
|
||||
void open(){
|
||||
//emulator.openDoor();
|
||||
@@ -109,7 +91,7 @@ void modBusPolling(void *parameter)
|
||||
u_int8_t pos = 255;
|
||||
void loop() override
|
||||
{
|
||||
u_int8_t position = HoermannSingleton::getInstance()->getEmulator()->getState().doorCurrentPosition;
|
||||
u_int8_t position = mainComponent->getEmulator()->getState().doorCurrentPosition;
|
||||
if(pos != position){
|
||||
this->position = (float) position / 200.0;
|
||||
this->publish_state();
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome.h"
|
||||
#include "Arduino.h"
|
||||
#include "hciemulator.h"
|
||||
//#include "cover.h"
|
||||
|
||||
#define RS485 Serial2
|
||||
#define TX_ON 25
|
||||
//#define configMAX_PRIORITIES 25
|
||||
|
||||
#define TAG "hoermann_door"
|
||||
|
||||
|
||||
void modBusPolling(void *parameter);
|
||||
|
||||
class HoermannSingleton {
|
||||
public:
|
||||
HoermannSingleton() {
|
||||
emulator;
|
||||
}
|
||||
static HoermannSingleton* instance_;
|
||||
HCIEmulator emulator;
|
||||
TaskHandle_t modBusTask;
|
||||
bool hasBeenInitialized = false;
|
||||
|
||||
public:
|
||||
static HoermannSingleton* getInstance(){
|
||||
if(instance_ == nullptr){
|
||||
instance_ = new HoermannSingleton();
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
|
||||
void initializeEmulator(){
|
||||
if(hasBeenInitialized) return;
|
||||
hasBeenInitialized = true;
|
||||
RS485.begin(57600, SERIAL_8E1, 16, 17);
|
||||
pinMode(TX_ON, OUTPUT);
|
||||
digitalWrite(TX_ON, LOW);
|
||||
|
||||
xTaskCreatePinnedToCore(
|
||||
modBusPolling, // Function to implement the task
|
||||
"ModBusTask", // Name of the task
|
||||
10000, // Stack size in words
|
||||
NULL, // Task input parameter
|
||||
// 1, // Priority of the task
|
||||
configMAX_PRIORITIES - 1,
|
||||
&modBusTask, // Task handle.
|
||||
1 // Core where the task should run
|
||||
);
|
||||
}
|
||||
HCIEmulator *getEmulator(){
|
||||
return &emulator;
|
||||
}
|
||||
};
|
||||
|
||||
HoermannSingleton* HoermannSingleton::instance_ = nullptr;
|
||||
|
||||
//DoorManager *DoorManager::getInstance()
|
||||
|
||||
|
||||
volatile unsigned long lastCall = 0;
|
||||
volatile unsigned long maxPeriod = 0;
|
||||
void modBusPolling(void *parameter)
|
||||
{
|
||||
auto emulator = HoermannSingleton::getInstance()->getEmulator();
|
||||
while (true)
|
||||
{
|
||||
if (lastCall > 0)
|
||||
{
|
||||
maxPeriod = _max(micros() - lastCall, maxPeriod);
|
||||
}
|
||||
lastCall = micros();
|
||||
emulator->poll();
|
||||
vTaskDelay(1);
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "hciemulator.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
#define CHECKCHANGEDSET(Target, Value, Flag) \
|
||||
if ((Target) != (Value)) \
|
||||
{ \
|
||||
@@ -22,18 +22,23 @@ void LogCore(int Level, const char *msg, const unsigned char *data = NULL, size_
|
||||
}
|
||||
if (data != NULL && datalen > 0)
|
||||
{
|
||||
String newmsg(msg);
|
||||
//std::string newmsg(msg);
|
||||
char* newmsg = (char*)malloc(strlen(msg) + datalen * 3 + 1);
|
||||
strncpy(newmsg, msg, strlen(msg) + 1);
|
||||
newmsg[strlen(msg)] = '\0';
|
||||
char str[4];
|
||||
for (size_t i = 0; i < datalen; i++)
|
||||
{
|
||||
snprintf(str, sizeof(str), "%02x ", data[i]);
|
||||
newmsg += str;
|
||||
str[3] = '\0';
|
||||
strncat(newmsg, str, sizeof(str));
|
||||
}
|
||||
Serial.println(newmsg);
|
||||
ESP_LOGD(TAG, newmsg);
|
||||
free(newmsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(msg);
|
||||
ESP_LOGD(TAG, msg);
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -50,6 +55,12 @@ void HCIEmulator::setLogLevel(int level)
|
||||
hciloglevel = level;
|
||||
}
|
||||
|
||||
//#ifdef USE_ESP_IDF
|
||||
uint16_t HCIEmulator::word(uint8_t high, uint8_t low){
|
||||
return (uint16_t) ((high << 8) | low);
|
||||
}
|
||||
//#endif
|
||||
|
||||
// modbus crc calculation borrowed from:
|
||||
// https://github.com/yaacov/ArduinoModbusSlave
|
||||
#define MODBUS_CRC_LENGTH 2
|
||||
@@ -98,14 +109,15 @@ uint16_t calculateCRC(uint8_t *buffer, int length)
|
||||
return crc;
|
||||
}
|
||||
|
||||
HCIEmulator::HCIEmulator()
|
||||
HCIEmulator::HCIEmulator(esphome::InternalGPIOPin* pin, esphome::uart::UARTComponent* uart)
|
||||
{
|
||||
m_state.valid = false;
|
||||
m_statemachine = WAITING;
|
||||
m_rxlen = m_txlen = 0;
|
||||
m_recvTime = m_lastStateTime = 0;
|
||||
m_skipFrame = false;
|
||||
m_port = &Serial2;
|
||||
m_port = uart;
|
||||
m_pin = pin;
|
||||
m_statusCallback = NULL;
|
||||
setLogLevel(DEFAULTLOGLEVEL);
|
||||
};
|
||||
@@ -122,7 +134,13 @@ void HCIEmulator::poll()
|
||||
if (m_port->available() > 0)
|
||||
{
|
||||
// Serial.println("got data");
|
||||
m_rxlen += m_port->readBytes((char *)(m_rxbuffer + m_rxlen), _min((int)(255 - m_rxlen), m_port->available()));
|
||||
int bytesToRead = std::min((int)(255 - m_rxlen), m_port->available());
|
||||
if(m_port->read_array((uint8_t *)(m_rxbuffer + m_rxlen), bytesToRead)) {
|
||||
m_rxlen += bytesToRead;
|
||||
} else {
|
||||
Log(LL_ERROR, "Error reading from UART");
|
||||
//m_port->flush();
|
||||
}
|
||||
if (m_rxlen > 254)
|
||||
{
|
||||
Log(LL_ERROR, "RX Bufferoverflow, skip next Frame");
|
||||
@@ -130,16 +148,16 @@ void HCIEmulator::poll()
|
||||
m_rxlen = 0;
|
||||
m_skipFrame = true;
|
||||
}
|
||||
m_recvTime = micros();
|
||||
m_recvTime = esphome::micros();
|
||||
}
|
||||
|
||||
// Serial.printf("Data % x\n", m_txbuffer);
|
||||
// check frame, process frame
|
||||
if (m_rxlen > 0 && (micros() - m_recvTime > T3_5))
|
||||
if (m_rxlen > 0 && (esphome::micros() - m_recvTime > T3_5))
|
||||
{
|
||||
// Serial.printf("Act on it % x\n", m_txbuffer);
|
||||
// check last action timeout -> reset > then 2sec
|
||||
if (m_statemachine != WAITING && m_lastStateTime + 2000 < millis())
|
||||
if (m_statemachine != WAITING && m_lastStateTime + 2000 < esphome::millis())
|
||||
{
|
||||
m_statemachine = WAITING;
|
||||
}
|
||||
@@ -158,22 +176,23 @@ void HCIEmulator::poll()
|
||||
m_txbuffer[(m_txlen - MODBUS_CRC_LENGTH) + 1] = crc >> 8;
|
||||
|
||||
// send data
|
||||
m_lastSendTime = micros() - m_recvTime;
|
||||
m_lastSendTime = esphome::micros() - m_recvTime;
|
||||
|
||||
// Log(LL_DEBUG, ("ST:"+String(m_lastSendTime)).c_str());
|
||||
|
||||
digitalWrite(TX_ON, HIGH);
|
||||
m_pin->digital_write(true);
|
||||
|
||||
// Log3(LL_DEBUG, "write data: ");
|
||||
m_port->write(m_txbuffer, m_txlen);
|
||||
m_port->write_array(m_txbuffer, m_txlen);
|
||||
Log3(LL_DEBUG, "Response: ", m_txbuffer, m_txlen);
|
||||
delayMicroseconds(m_txlen * 9 * 22); // 8 bits + par * Bittime 18 micros on 57600 bauds
|
||||
digitalWrite(TX_ON, LOW);
|
||||
esphome::delayMicroseconds(m_txlen * 9 * 22); // 8 bits + par * Bittime 18 micros on 57600 bauds
|
||||
m_pin->digital_write(false);
|
||||
m_txlen = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("skipped frame");
|
||||
ESP_LOGD(TAG, "skipped frame");
|
||||
}
|
||||
|
||||
m_skipFrame = false;
|
||||
@@ -274,10 +293,10 @@ void HCIEmulator::processDeviceStatusFrame()
|
||||
m_txbuffer[7] = 0x02;
|
||||
m_txbuffer[8] = 0x10;
|
||||
m_statemachine = STARTOPENDOOR_RELEASE;
|
||||
m_lastStateTime = millis();
|
||||
m_lastStateTime = esphome::millis();
|
||||
break;
|
||||
case STARTOPENDOOR_RELEASE:
|
||||
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < millis())
|
||||
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < esphome::millis())
|
||||
{
|
||||
m_txbuffer[7] = 0x01;
|
||||
m_txbuffer[8] = 0x10;
|
||||
@@ -290,10 +309,10 @@ void HCIEmulator::processDeviceStatusFrame()
|
||||
m_txbuffer[7] = 0x02;
|
||||
m_txbuffer[8] = 0x20;
|
||||
m_statemachine = STARTCLOSEDOOR_RELEASE;
|
||||
m_lastStateTime = millis();
|
||||
m_lastStateTime = esphome::millis();
|
||||
break;
|
||||
case STARTCLOSEDOOR_RELEASE:
|
||||
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < millis())
|
||||
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < esphome::millis())
|
||||
{
|
||||
m_txbuffer[7] = 0x01;
|
||||
m_txbuffer[8] = 0x20;
|
||||
@@ -306,10 +325,10 @@ void HCIEmulator::processDeviceStatusFrame()
|
||||
m_txbuffer[7] = 0x02;
|
||||
m_txbuffer[8] = 0x40;
|
||||
m_statemachine = STARTSTOPDOOR_RELEASE;
|
||||
m_lastStateTime = millis();
|
||||
m_lastStateTime = esphome::millis();
|
||||
break;
|
||||
case STARTSTOPDOOR_RELEASE:
|
||||
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < millis())
|
||||
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < esphome::millis())
|
||||
{
|
||||
m_txbuffer[7] = 0x01;
|
||||
m_txbuffer[8] = 0x40;
|
||||
@@ -322,10 +341,10 @@ void HCIEmulator::processDeviceStatusFrame()
|
||||
m_txbuffer[7] = 0x02;
|
||||
m_txbuffer[9] = 0x40;
|
||||
m_statemachine = STARTVENTPOSITION_RELEASE;
|
||||
m_lastStateTime = millis();
|
||||
m_lastStateTime = esphome::millis();
|
||||
break;
|
||||
case STARTVENTPOSITION_RELEASE:
|
||||
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < millis())
|
||||
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < esphome::millis())
|
||||
{
|
||||
m_txbuffer[7] = 0x01;
|
||||
m_txbuffer[9] = 0x40;
|
||||
@@ -338,11 +357,11 @@ void HCIEmulator::processDeviceStatusFrame()
|
||||
m_txbuffer[7] = 0x02;
|
||||
m_txbuffer[9] = 0x04;
|
||||
m_statemachine = STARTOPENDOORHALF_RELEASE;
|
||||
m_lastStateTime = millis();
|
||||
m_lastStateTime = esphome::millis();
|
||||
break;
|
||||
|
||||
case STARTOPENDOORHALF_RELEASE:
|
||||
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < millis())
|
||||
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < esphome::millis())
|
||||
{
|
||||
m_txbuffer[7] = 0x01;
|
||||
m_txbuffer[9] = 0x04;
|
||||
@@ -355,10 +374,10 @@ void HCIEmulator::processDeviceStatusFrame()
|
||||
m_txbuffer[7] = 0x10;
|
||||
m_txbuffer[9] = 0x02;
|
||||
m_statemachine = STARTTOGGLELAMP_RELEASE;
|
||||
m_lastStateTime = millis();
|
||||
m_lastStateTime = esphome::millis();
|
||||
break;
|
||||
case STARTTOGGLELAMP_RELEASE:
|
||||
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < millis())
|
||||
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < esphome::millis())
|
||||
{
|
||||
m_txbuffer[7] = 0x08;
|
||||
m_txbuffer[9] = 0x02;
|
||||
@@ -432,7 +451,7 @@ void HCIEmulator::openDoor()
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_lastStateTime = millis();
|
||||
m_lastStateTime = esphome::millis();
|
||||
m_statemachine = STARTOPENDOOR;
|
||||
}
|
||||
|
||||
@@ -442,7 +461,7 @@ void HCIEmulator::openDoorHalf()
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_lastStateTime = millis();
|
||||
m_lastStateTime = esphome::millis();
|
||||
m_statemachine = STARTOPENDOORHALF;
|
||||
}
|
||||
|
||||
@@ -452,7 +471,7 @@ void HCIEmulator::closeDoor()
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_lastStateTime = millis();
|
||||
m_lastStateTime = esphome::millis();
|
||||
m_statemachine = STARTCLOSEDOOR;
|
||||
}
|
||||
|
||||
@@ -462,7 +481,7 @@ void HCIEmulator::stopDoor()
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_lastStateTime = millis();
|
||||
m_lastStateTime = esphome::millis();
|
||||
m_statemachine = STARTSTOPDOOR;
|
||||
}
|
||||
|
||||
@@ -472,7 +491,7 @@ void HCIEmulator::toggleLamp()
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_lastStateTime = millis();
|
||||
m_lastStateTime = esphome::millis();
|
||||
m_statemachine = STARTTOGGLELAMP;
|
||||
}
|
||||
|
||||
@@ -482,7 +501,7 @@ void HCIEmulator::ventilationPosition()
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_lastStateTime = millis();
|
||||
m_lastStateTime = esphome::millis();
|
||||
m_statemachine = STARTVENTPOSITION;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#ifndef __hciemulator_h
|
||||
#define __hciemulator_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Stream.h>
|
||||
#include <SoftwareSerial.h>
|
||||
#ifdef USE_ESP_IDF
|
||||
//#include <cstdint>
|
||||
//#include <functional>
|
||||
//#include <algorithm>
|
||||
#endif
|
||||
|
||||
#include "esphome/components/uart/uart.h"
|
||||
|
||||
#define LL_OFF 0
|
||||
#define LL_ERROR 1
|
||||
@@ -26,7 +30,9 @@
|
||||
// intercharacter must be 1.5T or 1.5 times longer than a normal character and thus
|
||||
// 1.5T = 1.04167ms * 1.5 = 1.5625ms. A frame delay is 3.5T.
|
||||
#define T1_5 750
|
||||
#define T3_5 4800 // 1750
|
||||
#define T3_5 4800 //
|
||||
|
||||
static const char *const TAG = "HCIEmulator";
|
||||
|
||||
enum DoorState : uint8_t
|
||||
{
|
||||
@@ -75,7 +81,7 @@ class HCIEmulator
|
||||
public:
|
||||
typedef std::function<void(const SHCIState &)> callback_function_t;
|
||||
|
||||
HCIEmulator();
|
||||
HCIEmulator(esphome::InternalGPIOPin* pin, esphome::uart::UARTComponent* uart);
|
||||
|
||||
void poll();
|
||||
|
||||
@@ -88,7 +94,7 @@ public:
|
||||
|
||||
const SHCIState &getState()
|
||||
{
|
||||
if (micros() - m_recvTime > 2000000)
|
||||
if (esphome::micros() - m_recvTime > 2000000)
|
||||
{
|
||||
// 2 sec without statusmessage
|
||||
m_state.valid = false;
|
||||
@@ -98,7 +104,7 @@ public:
|
||||
|
||||
unsigned long getMessageAge()
|
||||
{
|
||||
return micros() - m_recvTime;
|
||||
return esphome::micros() - m_recvTime;
|
||||
}
|
||||
|
||||
int getLogLevel();
|
||||
@@ -111,10 +117,16 @@ protected:
|
||||
void processDeviceStatusFrame();
|
||||
void processDeviceBusScanFrame();
|
||||
void processBroadcastStatusFrame();
|
||||
//#ifdef USE_ESP_IDF
|
||||
uint16_t word(uint8_t high, uint8_t low);
|
||||
//#endif
|
||||
|
||||
private:
|
||||
callback_function_t m_statusCallback;
|
||||
Stream *m_port;
|
||||
|
||||
esphome::InternalGPIOPin* m_pin;
|
||||
esphome::uart::UARTComponent* m_port;
|
||||
|
||||
SHCIState m_state;
|
||||
StateMachine m_statemachine;
|
||||
|
||||
@@ -125,10 +137,10 @@ private:
|
||||
size_t m_rxlen;
|
||||
size_t m_txlen;
|
||||
|
||||
unsigned char m_rxbuffer[255] = {
|
||||
uint8_t m_rxbuffer[255] = {
|
||||
0,
|
||||
};
|
||||
unsigned char m_txbuffer[255] = {
|
||||
uint8_t m_txbuffer[255] = {
|
||||
0,
|
||||
};
|
||||
|
||||
|
||||
89
external_components/hoermann_door/hoermann.h
Normal file
89
external_components/hoermann_door/hoermann.h
Normal file
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
class HoermannMainComponent;
|
||||
#include "hciemulator.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace hoermann_door {
|
||||
|
||||
static const char *const TAG = "Hoermann";
|
||||
|
||||
void dispatcherFn(void *arg);
|
||||
|
||||
class HoermannMainComponent: public Component{
|
||||
protected:
|
||||
HCIEmulator* emulator;
|
||||
TaskHandle_t modBusTask;
|
||||
|
||||
uart::UARTComponent* _uart;
|
||||
InternalGPIOPin* _tx_on;
|
||||
|
||||
volatile bool set_continue_ = true;
|
||||
volatile unsigned long lastCall = 0;
|
||||
volatile unsigned long maxPeriod = 0;
|
||||
|
||||
public:
|
||||
|
||||
void set_seriel_connection(uart::UARTComponent* uart){
|
||||
this->_uart = uart;
|
||||
}
|
||||
void set_tx_on_pin(InternalGPIOPin* pin){
|
||||
this->_tx_on = pin;
|
||||
}
|
||||
HCIEmulator* getEmulator(){
|
||||
return emulator;
|
||||
}
|
||||
|
||||
void setup() override {
|
||||
|
||||
this->_tx_on->setup();
|
||||
this->emulator = new HCIEmulator(this->_tx_on, this->_uart);
|
||||
|
||||
this->_tx_on->digital_write(false);
|
||||
this->set_continue_ = true;
|
||||
xTaskCreatePinnedToCore(
|
||||
dispatcherFn, // Function to implement the task
|
||||
"ModBusTask", // Name of the task
|
||||
10000, // Stack size in words
|
||||
this, // Task input parameter
|
||||
// 1, // Priority of the task
|
||||
configMAX_PRIORITIES - 1,
|
||||
&modBusTask, // Task handle.
|
||||
1 // Core where the task should run
|
||||
);
|
||||
}
|
||||
|
||||
void modBusPolling(void *parameter)
|
||||
{
|
||||
while (set_continue_)
|
||||
{
|
||||
if (lastCall > 0)
|
||||
{
|
||||
maxPeriod = std::max((micros() - lastCall), (unsigned long)maxPeriod);
|
||||
}
|
||||
lastCall = micros();
|
||||
emulator->poll();
|
||||
vTaskDelay(1);
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void dump_config() override {
|
||||
ESP_LOGCONFIG(TAG, "hoermann_door_component:");
|
||||
ESP_LOGCONFIG(TAG, " UART: %d", this->_uart->get_baud_rate());
|
||||
//LOG_PIN(TAG, this->_tx_on);
|
||||
}
|
||||
};
|
||||
|
||||
void dispatcherFn(void *arg)
|
||||
{
|
||||
HoermannMainComponent *x = (HoermannMainComponent *)arg;
|
||||
x->modBusPolling(arg);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
|
||||
class NbsLightManager;
|
||||
|
||||
#include "esphome.h"
|
||||
#include "Arduino.h"
|
||||
#include "hciemulator.h"
|
||||
#include "door_singleton.h"
|
||||
#include "hoermann.h"
|
||||
//#include "cover.h"
|
||||
|
||||
#define RS485 Serial2
|
||||
@@ -20,13 +21,14 @@ namespace hoermann_door {
|
||||
// Custom binary output, for exposing binary states
|
||||
class NbsLightManager: public binary::BinaryLightOutput, public light::LightState {
|
||||
protected:
|
||||
HoermannSingleton *single;
|
||||
public:
|
||||
void setup() override {
|
||||
//single = HoermannSingleton::getInstance();
|
||||
//single->initializeGetInstance
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool lastState = false;
|
||||
bool firstState = false;
|
||||
void loop() override {
|
||||
@@ -45,15 +47,15 @@ class NbsLightManager: public binary::BinaryLightOutput, public light::LightStat
|
||||
class NbsLightOutput: public output::BinaryOutput, public Component{
|
||||
|
||||
light::LightState *callback;
|
||||
HoermannSingleton *single;
|
||||
bool lastState = false;
|
||||
bool firstState = true;
|
||||
HoermannMainComponent *mainComponent;
|
||||
|
||||
public:
|
||||
|
||||
virtual void write_state(bool state){
|
||||
if(lastState != state){
|
||||
single->getEmulator()->toggleLamp();
|
||||
mainComponent->getEmulator()->toggleLamp();
|
||||
//lastState = state;
|
||||
}
|
||||
}
|
||||
@@ -62,21 +64,24 @@ class NbsLightOutput: public output::BinaryOutput, public Component{
|
||||
if(callback == nullptr) ESP_LOGW("Hoermann_door(Light)", "Got Nullable callback");
|
||||
this->callback = callback;
|
||||
}
|
||||
void set_emulator_component(HoermannMainComponent* component){
|
||||
this->mainComponent = component;
|
||||
}
|
||||
|
||||
void loop() override {
|
||||
if(!single->getEmulator()->getState().valid) false;
|
||||
if(firstState || single->getEmulator()->getState().lampOn != lastState){
|
||||
if(!mainComponent->getEmulator()->getState().valid) false;
|
||||
if(firstState || mainComponent->getEmulator()->getState().lampOn != lastState){
|
||||
//ESP_LOGD("Test", "I have no idea");
|
||||
lastState = single->getEmulator()->getState().lampOn;
|
||||
lastState = mainComponent->getEmulator()->getState().lampOn;
|
||||
if(lastState == true){
|
||||
ESP_LOGD("Hoermann_door(Light)", "Light State ON");
|
||||
ESP_LOGD(TAG, "Hoermann_door(Light)", "Light State ON");
|
||||
|
||||
auto call = callback->make_call();
|
||||
call.set_state(true);
|
||||
call.perform();
|
||||
}
|
||||
else {
|
||||
ESP_LOGD("Hoermann_door(Light)", "Light State OFF");
|
||||
ESP_LOGD(TAG, "Hoermann_door(Light)", "Light State OFF");
|
||||
auto call = callback->make_call();
|
||||
call.set_state(false);
|
||||
call.perform();
|
||||
@@ -87,8 +92,7 @@ class NbsLightOutput: public output::BinaryOutput, public Component{
|
||||
}
|
||||
|
||||
void setup() override {
|
||||
single = HoermannSingleton::getInstance();
|
||||
single->initializeEmulator();
|
||||
|
||||
}
|
||||
|
||||
void turn_on() override {
|
||||
|
||||
@@ -2,23 +2,29 @@ import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import output, light
|
||||
from esphome.const import CONF_ID
|
||||
from . import HoermannDoor
|
||||
|
||||
hoermann_cover_ns = cg.esphome_ns.namespace('hoermann_door')
|
||||
HoermannCoverLight = hoermann_cover_ns.class_('NbsLightOutput', output.BinaryOutput, cg.Component)
|
||||
CONF_STATE_CALLBACK = "state_callback"
|
||||
CONF_HOERMANN_CONTROLLER = "hoermann_controller"
|
||||
|
||||
CONFIG_SCHEMA = output.BINARY_OUTPUT_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_ID): cv.declare_id(HoermannCoverLight),
|
||||
cv.Required(CONF_STATE_CALLBACK): cv.use_id(light.LightState)
|
||||
cv.Required(CONF_STATE_CALLBACK): cv.use_id(light.LightState),
|
||||
cv.Required(CONF_HOERMANN_CONTROLLER): cv.use_id(HoermannDoor)
|
||||
}).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield output.register_output(var, config)
|
||||
await cg.register_component(var, config)
|
||||
await output.register_output(var, config)
|
||||
|
||||
callback = yield cg.get_variable(config[CONF_STATE_CALLBACK])
|
||||
callback = await cg.get_variable(config[CONF_STATE_CALLBACK])
|
||||
cg.add(var.set_state_callback(callback))
|
||||
|
||||
cg.add_library("plerup/EspSoftwareSerial", "8.2.0")
|
||||
controller = await cg.get_variable(config[CONF_HOERMANN_CONTROLLER])
|
||||
cg.add(var.set_emulator_component(controller))
|
||||
|
||||
# cg.add_library("plerup/EspSoftwareSerial", "8.2.0")
|
||||
25
garage1.yaml
25
garage1.yaml
@@ -3,8 +3,11 @@ substitutions:
|
||||
|
||||
esphome:
|
||||
name: garage${garageSide}
|
||||
platform: ESP32
|
||||
board: esp32dev
|
||||
|
||||
esp32:
|
||||
board: wemos_d1_mini32
|
||||
framework:
|
||||
type: esp-idf
|
||||
|
||||
ota:
|
||||
- platform: esphome
|
||||
@@ -31,6 +34,22 @@ external_components:
|
||||
cover:
|
||||
- platform: hoermann_door
|
||||
name: door_${garageSide}
|
||||
hoermann_controller: door_controll_internal
|
||||
|
||||
uart:
|
||||
rx_pin: 16
|
||||
tx_pin: 17
|
||||
baud_rate: 57600
|
||||
id: hm_connection
|
||||
data_bits: 8 # Standard
|
||||
parity: EVEN # NON Standard, None would be standard
|
||||
stop_bits: 1 # Standard
|
||||
|
||||
|
||||
hoermann_door:
|
||||
id: door_controll_internal
|
||||
uart_connection: hm_connection
|
||||
tx_pin: 25
|
||||
|
||||
light:
|
||||
- platform: binary
|
||||
@@ -42,5 +61,7 @@ output:
|
||||
- id: light_out
|
||||
platform: hoermann_door
|
||||
state_callback: lamp_id_${garageSide}
|
||||
hoermann_controller: door_controll_internal
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user