// Must disable logging if using logging in main.cpp or in other custom components for the | |
// __c causes a section type conflict with __c thingy | |
// you can enable logging and use it if you enable this in logger: | |
/* | |
logger: | |
level: DEBUG | |
esp8266_store_log_strings_in_flash: False | |
*/ | |
//#define APE_LOGGING | |
// take advantage of LOG_ defines to decide which code to include | |
#ifdef LOG_BINARY_OUTPUT | |
#define APE_BINARY_OUTPUT | |
#endif | |
#ifdef LOG_BINARY_SENSOR | |
#define APE_BINARY_SENSOR | |
#endif | |
#ifdef LOG_SENSOR | |
#define APE_SENSOR | |
#endif | |
static const char *TAGape = "ape"; | |
#define APE_CMD_DIGITAL_READ 0 | |
#define APE_CMD_WRITE_ANALOG 2 | |
#define APE_CMD_WRITE_DIGITAL_HIGH 3 | |
#define APE_CMD_WRITE_DIGITAL_LOW 4 | |
#define APE_CMD_SETUP_PIN_OUTPUT 5 | |
#define APE_CMD_SETUP_PIN_INPUT_PULLUP 6 | |
#define APE_CMD_SETUP_PIN_INPUT 7 | |
// 8 analog registers.. A0 to A7 | |
// A4 and A5 not supported due to I2C | |
#define CMD_ANALOG_READ_A0 0b1000 // 0x8 | |
// .... | |
#define CMD_ANALOG_READ_A7 0b1111 // 0xF | |
#define CMD_SETUP_ANALOG_INTERNAL 0x10 | |
#define CMD_SETUP_ANALOG_DEFAULT 0x11 | |
#define get_ape(constructor) static_cast<ArduinoPortExpander *>(constructor.get_component(0)) | |
#define ape_binary_output(ape, pin) get_ape(ape)->get_binary_output(pin) | |
#define ape_binary_sensor(ape, pin) get_ape(ape)->get_binary_sensor(pin) | |
#define ape_analog_input(ape, pin) get_ape(ape)->get_analog_input(pin) | |
class ArduinoPortExpander; | |
using namespace esphome; | |
#ifdef APE_BINARY_OUTPUT | |
class ApeBinaryOutput : public output::BinaryOutput | |
{ | |
public: | |
ApeBinaryOutput(ArduinoPortExpander *parent, uint8_t pin) | |
{ | |
this->parent_ = parent; | |
this->pin_ = pin; | |
} | |
void write_state(bool state) override; | |
uint8_t get_pin() { return this->pin_; } | |
protected: | |
ArduinoPortExpander *parent_; | |
uint8_t pin_; | |
// Pins are setup as output after the state is written, Arduino has no open drain outputs, after setting an output it will either sink or source thus activating outputs writen to false during a flick. | |
bool setup_{true}; | |
bool state_{false}; | |
friend class ArduinoPortExpander; | |
}; | |
#endif | |
#ifdef APE_BINARY_SENSOR | |
class ApeBinarySensor : public binary_sensor::BinarySensor | |
{ | |
public: | |
ApeBinarySensor(ArduinoPortExpander *parent, uint8_t pin) | |
{ | |
this->pin_ = pin; | |
} | |
uint8_t get_pin() { return this->pin_; } | |
protected: | |
uint8_t pin_; | |
}; | |
#endif | |
#ifdef APE_SENSOR | |
class ApeAnalogInput : public sensor::Sensor | |
{ | |
public: | |
ApeAnalogInput(ArduinoPortExpander *parent, uint8_t pin) | |
{ | |
this->pin_ = pin; | |
} | |
uint8_t get_pin() { return this->pin_; } | |
protected: | |
uint8_t pin_; | |
}; | |
#endif | |
class ArduinoPortExpander : public Component, public I2CDevice | |
{ | |
public: | |
ArduinoPortExpander(I2CBus *bus, uint8_t address, bool vref_default = false) | |
{ | |
set_i2c_address(address); | |
set_i2c_bus(bus); | |
this->vref_default_ = vref_default; | |
} | |
void setup() override | |
{ | |
#ifdef APE_LOGGING | |
ESP_LOGCONFIG(TAGape, "Setting up ArduinoPortExpander at %#02x ...", address_); | |
#endif | |
/* We cannot setup as usual as arduino boots later than esp8266 | |
Poll i2c bus for our Arduino for a n seconds instead of failing fast, | |
also this is important as pin setup (INPUT_PULLUP, OUTPUT it's done once) | |
*/ | |
this->configure_timeout_ = millis() + 5000; | |
} | |
void loop() override | |
{ | |
if (millis() < this->configure_timeout_) | |
{ | |
bool try_configure = millis() % 100 > 50; | |
if (try_configure == this->configure_) | |
return; | |
this->configure_ = try_configure; | |
if (ERROR_OK == this->read_register(APE_CMD_DIGITAL_READ, const_cast<uint8_t *>(this->read_buffer_), 3)) | |
{ | |
#ifdef APE_LOGGING | |
ESP_LOGCONFIG(TAGape, "ArduinoPortExpander found at %#02x", address_); | |
#endif | |
delay(10); | |
if (this->vref_default_) | |
{ | |
this->write_register(CMD_SETUP_ANALOG_DEFAULT, nullptr, 0); // 0: unused | |
} | |
// Config success | |
this->configure_timeout_ = 0; | |
this->status_clear_error(); | |
#ifdef APE_BINARY_SENSOR | |
for (ApeBinarySensor *pin : this->input_pins_) | |
{ | |
App.feed_wdt(); | |
uint8_t pinNo = pin->get_pin(); | |
#ifdef APE_LOGGING | |
ESP_LOGCONFIG(TAGape, "Setup input pin %d", pinNo); | |
#endif | |
this->write_register(APE_CMD_SETUP_PIN_INPUT_PULLUP, &pinNo, 1); | |
delay(20); | |
} | |
#endif | |
#ifdef APE_BINARY_OUTPUT | |
for (ApeBinaryOutput *output : this->output_pins_) | |
{ | |
if (!output->setup_) | |
{ // this output has a valid value already | |
this->write_state(output->pin_, output->state_, true); | |
App.feed_wdt(); | |
delay(20); | |
} | |
} | |
#endif | |
#ifdef APE_SENSOR | |
for (ApeAnalogInput *sensor : this->analog_pins_) | |
{ | |
App.feed_wdt(); | |
uint8_t pinNo = sensor->get_pin(); | |
#ifdef APE_LOGGING | |
ESP_LOGCONFIG(TAGape, "Setup analog input pin %d", pinNo); | |
#endif | |
this->write_register(APE_CMD_SETUP_PIN_INPUT, &pinNo, 1); | |
delay(20); | |
} | |
#endif | |
return; | |
} | |
// Still not answering | |
return; | |
} | |
if (this->configure_timeout_ != 0 && millis() > this->configure_timeout_) | |
{ | |
#ifdef APE_LOGGING | |
ESP_LOGE(TAGape, "ArduinoPortExpander NOT found at %#02x", address_); | |
#endif | |
this->mark_failed(); | |
return; | |
} | |
#ifdef APE_BINARY_SENSOR | |
if (ERROR_OK != this->read_register(APE_CMD_DIGITAL_READ, const_cast<uint8_t *>(this->read_buffer_), 3)) | |
{ | |
#ifdef APE_LOGGING | |
ESP_LOGE(TAGape, "Error reading. Reconfiguring pending."); | |
#endif | |
this->status_set_error(); | |
this->configure_timeout_ = millis() + 5000; | |
return; | |
} | |
for (ApeBinarySensor *pin : this->input_pins_) | |
{ | |
uint8_t pinNo = pin->get_pin(); | |
uint8_t bit = pinNo % 8; | |
uint8_t value = pinNo < 8 ? this->read_buffer_[0] : pinNo < 16 ? this->read_buffer_[1] : this->read_buffer_[2]; | |
bool ret = value & (1 << bit); | |
if (this->initial_state_) | |
pin->publish_initial_state(ret); | |
else | |
pin->publish_state(ret); | |
} | |
#endif | |
#ifdef APE_SENSOR | |
for (ApeAnalogInput *pin : this->analog_pins_) | |
{ | |
uint8_t pinNo = pin->get_pin(); | |
pin->publish_state(analogRead(pinNo)); | |
} | |
#endif | |
this->initial_state_ = false; | |
} | |
#ifdef APE_SENSOR | |
uint16_t analogRead(uint8_t pin) | |
{ | |
bool ok = (ERROR_OK == this->read_register((uint8_t)(CMD_ANALOG_READ_A0 + pin), const_cast<uint8_t *>(this->read_buffer_), 2)); | |
#ifdef APE_LOGGING | |
ESP_LOGVV(TAGape, "analog read pin: %d ok: %d byte0: %d byte1: %d", pin, ok, this->read_buffer_[0], this->read_buffer_[1]); | |
#endif | |
uint16_t value = this->read_buffer_[0] | ((uint16_t)this->read_buffer_[1] << 8); | |
return value; | |
} | |
#endif | |
#ifdef APE_BINARY_OUTPUT | |
output::BinaryOutput *get_binary_output(uint8_t pin) | |
{ | |
ApeBinaryOutput *output = new ApeBinaryOutput(this, pin); | |
output_pins_.push_back(output); | |
return output; | |
} | |
#endif | |
#ifdef APE_BINARY_SENSOR | |
binary_sensor::BinarySensor *get_binary_sensor(uint8_t pin) | |
{ | |
ApeBinarySensor *binarySensor = new ApeBinarySensor(this, pin); | |
input_pins_.push_back(binarySensor); | |
return binarySensor; | |
} | |
#endif | |
#ifdef APE_SENSOR | |
sensor::Sensor *get_analog_input(uint8_t pin) | |
{ | |
ApeAnalogInput *input = new ApeAnalogInput(this, pin); | |
analog_pins_.push_back(input); | |
return input; | |
} | |
#endif | |
void write_state(uint8_t pin, bool state, bool setup = false) | |
{ | |
if (this->configure_timeout_ != 0) | |
return; | |
#ifdef APE_LOGGING | |
ESP_LOGD(TAGape, "Writing %d to pin %d", state, pin); | |
#endif | |
this->write_register(state ? APE_CMD_WRITE_DIGITAL_HIGH : APE_CMD_WRITE_DIGITAL_LOW, &pin, 1); | |
if (setup) | |
{ | |
App.feed_wdt(); | |
delay(20); | |
#ifdef APE_LOGGING | |
ESP_LOGI(TAGape, "Setup output pin %d", pin); | |
#endif | |
this->write_register(APE_CMD_SETUP_PIN_OUTPUT, &pin, 1); | |
} | |
} | |
protected: | |
bool configure_{true}; | |
bool initial_state_{true}; | |
uint8_t read_buffer_[3]{0, 0, 0}; | |
unsigned long configure_timeout_{5000}; | |
bool vref_default_{false}; | |
#ifdef APE_BINARY_OUTPUT | |
std::vector<ApeBinaryOutput *> output_pins_; | |
#endif | |
#ifdef APE_BINARY_SENSOR | |
std::vector<ApeBinarySensor *> input_pins_; | |
#endif | |
#ifdef APE_SENSOR | |
std::vector<ApeAnalogInput *> analog_pins_; | |
#endif | |
}; | |
#ifdef APE_BINARY_OUTPUT | |
void ApeBinaryOutput::write_state(bool state) | |
{ | |
this->state_ = state; | |
this->parent_->write_state(this->pin_, state, this->setup_); | |
this->setup_ = false; | |
} | |
#endif |
/* | |
Ports: | |
0 0 .. 13 13 | |
A0: 14, A1: 15, A2: 16, A3: 17: A4: 18: A5: 19: A6: 20, A7: 21 | |
port bits: 5 ... 0..32 | |
0: 0: 00000 | |
1: 1: 00001 | |
A7: 21: 10101 | |
*/ | |
#include <Arduino.h> | |
#include <Wire.h> | |
//#define DEBUG // remove debug so pin 0 and 1 can be used for IO | |
#define I2C_ADDRESS 8 | |
void onRequest(); | |
void onReceive(int); | |
void setup() | |
{ | |
#ifdef DEBUG | |
Serial.begin(115200); | |
Serial.println(F("Init ")); | |
#endif | |
analogReference(INTERNAL); | |
Wire.begin(I2C_ADDRESS); | |
Wire.onRequest(onRequest); | |
Wire.onReceive(onReceive); | |
#ifdef DEBUG | |
Serial.println(F("Wire ok")); | |
#endif | |
} | |
void loop() | |
{ | |
//int temp = analogRead(A1); | |
//Serial.println(temp); | |
} | |
volatile byte buffer[3]; | |
volatile byte len = 1; | |
#define DIGITAL_READ(b, pin, mask) \ | |
if (digitalRead(pin)) \ | |
buffer[b] |= mask; | |
void readDigital() | |
{ | |
len = 3; | |
buffer[0] = 0; | |
DIGITAL_READ(0, 0, 1); | |
DIGITAL_READ(0, 1, 2); | |
DIGITAL_READ(0, 2, 4); | |
DIGITAL_READ(0, 3, 8); | |
DIGITAL_READ(0, 4, 16); | |
DIGITAL_READ(0, 5, 32); | |
DIGITAL_READ(0, 6, 64); | |
DIGITAL_READ(0, 7, 128); | |
buffer[1] = 0; | |
DIGITAL_READ(1, 8, 1); | |
DIGITAL_READ(1, 9, 2); | |
DIGITAL_READ(1, 10, 4); | |
DIGITAL_READ(1, 11, 8); | |
DIGITAL_READ(1, 12, 16); | |
DIGITAL_READ(1, 13, 32); | |
DIGITAL_READ(1, A0, 64); | |
DIGITAL_READ(1, A1, 128); | |
buffer[2] = 0; | |
DIGITAL_READ(2, A2, 1); | |
DIGITAL_READ(2, A3, 2); | |
// I2C | |
//DIGITAL_READ(2, A4, 4); | |
//DIGITAL_READ(2, A5, 8); | |
// DIGITAL READ not supports on A3 .. A7 | |
#ifdef DEBUG_READ | |
Serial.print(F("Read 3 bytes: ")); | |
Serial.print(buffer[0]); | |
Serial.print(' '); | |
Serial.print(buffer[1]); | |
Serial.print(' '); | |
Serial.println(buffer[2]); | |
#endif | |
} | |
void readAnalog(int pin) | |
{ | |
int val = analogRead(A0 + pin); | |
len = 2; | |
buffer[0] = val & 0xFF; | |
buffer[1] = (val >> 8) & 0b11; | |
#ifdef DEBUG_READ | |
Serial.print(F("Read analog pin ")); | |
Serial.println(pin); | |
#endif | |
} | |
void onRequest() | |
{ | |
Wire.write(const_cast<uint8_t *>(buffer), len); | |
} | |
#define CMD_DIGITAL_READ 0x0 | |
#define CMD_WRITE_ANALOG 0x2 | |
#define CMD_WRITE_DIGITAL_HIGH 0x3 | |
#define CMD_WRITE_DIGITAL_LOW 0x4 | |
#define CMD_SETUP_PIN_OUTPUT 0x5 | |
#define CMD_SETUP_PIN_INPUT_PULLUP 0x6 | |
#define CMD_SETUP_PIN_INPUT 0x7 | |
// 8 analog registers.. A0 to A7 | |
// A4 and A5 not supported due to I2C | |
#define CMD_ANALOG_READ_A0 0b1000 // 0x8 | |
// .... | |
#define CMD_ANALOG_READ_A7 0b1111 // 0xF | |
#define CMD_SETUP_ANALOG_INTERNAL 0x10 | |
#define CMD_SETUP_ANALOG_DEFAULT 0x11 | |
void onReceive(int numBytes) | |
{ | |
#ifdef DEBUG_READ | |
Serial.print("Received bytes: "); | |
Serial.println(numBytes); | |
#endif | |
int cmd = Wire.read(); | |
switch (cmd) | |
{ | |
case CMD_DIGITAL_READ: | |
readDigital(); | |
break; | |
} | |
if (cmd >= CMD_ANALOG_READ_A0 && cmd <= CMD_ANALOG_READ_A7) | |
{ | |
readAnalog(cmd & 0b111); | |
return; | |
} | |
int pin = Wire.read(); | |
switch (cmd) | |
{ | |
case CMD_WRITE_DIGITAL_HIGH: | |
case CMD_WRITE_DIGITAL_LOW: | |
{ | |
bool output = cmd == CMD_WRITE_DIGITAL_HIGH; | |
digitalWrite(pin, output); | |
#ifdef DEBUG | |
Serial.print(F("Pin ")); | |
Serial.print(pin); | |
Serial.println(output ? F(" HIGH") : F(" LOW")); | |
#endif | |
break; | |
} | |
case CMD_WRITE_ANALOG: | |
{ | |
int val = Wire.read() & (Wire.read() << 8); | |
analogWrite(pin, val); | |
#ifdef DEBUG | |
Serial.print(F("Pin ")); | |
Serial.print(pin); | |
Serial.print(F(" Analog write ")); | |
Serial.println(val); | |
#endif | |
break; | |
} | |
case CMD_SETUP_PIN_OUTPUT: | |
pinMode(pin, OUTPUT); | |
#ifdef DEBUG | |
Serial.print(F("Pin ")); | |
Serial.print(pin); | |
Serial.println(F(" OUTPUT")); | |
#endif | |
break; | |
case CMD_SETUP_PIN_INPUT: | |
pinMode(pin, INPUT); | |
#ifdef DEBUG | |
Serial.print(F("Pin ")); | |
Serial.print(pin); | |
Serial.println(F("INPUT")); | |
#endif | |
break; | |
case CMD_SETUP_PIN_INPUT_PULLUP: | |
pinMode(pin, INPUT_PULLUP); | |
#ifdef DEBUG | |
Serial.print(F("Pin ")); | |
Serial.print(pin); | |
Serial.println(F("INPUT PULLUP")); | |
#endif | |
break; | |
case CMD_SETUP_ANALOG_INTERNAL: | |
analogReference(INTERNAL); | |
#ifdef DEBUG | |
Serial.println(F("Analog reference INTERNAL")); | |
#endif | |
break; | |
case CMD_SETUP_ANALOG_DEFAULT: | |
analogReference(DEFAULT); | |
#ifdef DEBUG | |
Serial.println(F("Analog reference DEFAULT")); | |
#endif | |
break; | |
} | |
} |
Having same issue, after update. Problem seems to be with the config file
I've updated the arduino_port_expander.h
I was able to compile in ESPHome. Tks!!!
Up and running, thank you!
Hi,
I was searching for a version for Arduino Mega and found this.
Unfortunately it was not working with the latest version of Esphome. I'm not a programmer, but by making a compare beetwen that version and yours, I succeeded to make it work.
I would be nice to make it official and publish in the Esphome site.
I've added the same comment in thebradleysanders github site.
// Must disable logging if using logging in main.cpp or in other custom components for the
// __c causes a section type conflict with __c thingy
// you can enable logging and use it if you enable this in logger:
/*
logger:
level: DEBUG
esp8266_store_log_strings_in_flash: False
*/
//#define APE_LOGGING
// take advantage of LOG_ defines to decide which code to include
#ifdef LOG_BINARY_OUTPUT
#define APE_BINARY_OUTPUT
#endif
#ifdef LOG_BINARY_SENSOR
#define APE_BINARY_SENSOR
#endif
#ifdef LOG_SENSOR
#define APE_SENSOR
#endif
static const char *TAGape = "ape";
#define APE_CMD_DIGITAL_READ 0
#define APE_CMD_WRITE_ANALOG 2
#define APE_CMD_WRITE_DIGITAL_HIGH 3
#define APE_CMD_WRITE_DIGITAL_LOW 4
#define APE_CMD_SETUP_PIN_OUTPUT 5
#define APE_CMD_SETUP_PIN_INPUT_PULLUP 6
#define APE_CMD_SETUP_PIN_INPUT 7
// 16 analog registers.. A0 to A15
// A4 and A5 on Arduino Uno not supported due to I2C
#define CMD_ANALOG_READ_A0 0b1000 // 0x8 = A0
// ....
#define CMD_ANALOG_READ_A15 10111 // 17 = A15 0x11
#define CMD_SETUP_ANALOG_INTERNAL 0x10
#define CMD_SETUP_ANALOG_DEFAULT 0x12
#define get_ape(constructor) static_cast<ArduinoPortExpander *>(constructor.get_component(0))
#define ape_binary_output(ape, pin) get_ape(ape)->get_binary_output(pin)
#define ape_binary_sensor(ape, pin) get_ape(ape)->get_binary_sensor(pin)
#define ape_analog_input(ape, pin) get_ape(ape)->get_analog_input(pin)
class ArduinoPortExpander;
using namespace esphome;
#ifdef APE_BINARY_OUTPUT
class ApeBinaryOutput : public output::BinaryOutput
{
public:
ApeBinaryOutput(ArduinoPortExpander *parent, uint8_t pin)
{
this->parent_ = parent;
this->pin_ = pin;
}
void write_state(bool state) override;
uint8_t get_pin() { return this->pin_; }
protected:
ArduinoPortExpander *parent_;
uint8_t pin_;
// Pins are setup as output after the state is written, Arduino has no open drain outputs, after setting an output it will either sink or source thus activating outputs writen to false during a flick.
bool setup_{true};
bool state_{false};
friend class ArduinoPortExpander;
};
#endif
#ifdef APE_BINARY_SENSOR
class ApeBinarySensor : public binary_sensor::BinarySensor
{
public:
ApeBinarySensor(ArduinoPortExpander *parent, uint8_t pin)
{
this->pin_ = pin;
}
uint8_t get_pin() { return this->pin_; }
protected:
uint8_t pin_;
};
#endif
#ifdef APE_SENSOR
class ApeAnalogInput : public sensor::Sensor
{
public:
ApeAnalogInput(ArduinoPortExpander *parent, uint8_t pin)
{
this->pin_ = pin;
}
uint8_t get_pin() { return this->pin_; }
protected:
uint8_t pin_;
};
#endif
class ArduinoPortExpander : public Component, public I2CDevice
{
public:
ArduinoPortExpander(I2CBus *bus, uint8_t address, bool vref_default = false)
{
set_i2c_address(address);
set_i2c_bus(bus);
this->vref_default_ = vref_default;
}
void setup() override
{
#ifdef APE_LOGGING
ESP_LOGCONFIG(TAGape, "Setting up ArduinoPortExpander at %#02x ...", address_);
#endif
/* We cannot setup as usual as arduino boots later than esp8266
Poll i2c bus for our Arduino for a n seconds instead of failing fast,
also this is important as pin setup (INPUT_PULLUP, OUTPUT it's done once)
*/
this->configure_timeout_ = millis() + 5000;
}
void loop() override
{
if (millis() < this->configure_timeout_)
{
bool try_configure = millis() % 100 > 50;
if (try_configure == this->configure_)
return;
this->configure_ = try_configure;
if (ERROR_OK == this->read_register(APE_CMD_DIGITAL_READ, const_cast<uint8_t *>(this->read_buffer_), 9)) //changed 3 to 9
{
#ifdef APE_LOGGING
ESP_LOGCONFIG(TAGape, "ArduinoPortExpander found at %#02x", address_);
#endif
delay(10);
if (this->vref_default_)
{
this->write_register(CMD_SETUP_ANALOG_DEFAULT, nullptr, 0); // 0: unused
}
// Config success
this->configure_timeout_ = 0;
this->status_clear_error();
#ifdef APE_BINARY_SENSOR
for (ApeBinarySensor *pin : this->input_pins_)
{
App.feed_wdt();
uint8_t pinNo = pin->get_pin();
#ifdef APE_LOGGING
ESP_LOGCONFIG(TAGape, "Setup input pin %d", pinNo);
#endif
this->write_register(APE_CMD_SETUP_PIN_INPUT_PULLUP, &pinNo, 1);
delay(20);
}
#endif
#ifdef APE_BINARY_OUTPUT
for (ApeBinaryOutput *output : this->output_pins_)
{
if (!output->setup_)
{ // this output has a valid value already
this->write_state(output->pin_, output->state_, true);
App.feed_wdt();
delay(20);
}
}
#endif
#ifdef APE_SENSOR
for (ApeAnalogInput *sensor : this->analog_pins_)
{
App.feed_wdt();
uint8_t pinNo = sensor->get_pin();
#ifdef APE_LOGGING
ESP_LOGCONFIG(TAGape, "Setup analog input pin %d", pinNo);
#endif
this->write_register(APE_CMD_SETUP_PIN_INPUT, &pinNo, 1);
delay(20);
}
#endif
return;
}
// Still not answering
return;
}
if (this->configure_timeout_ != 0 && millis() > this->configure_timeout_)
{
#ifdef APE_LOGGING
ESP_LOGE(TAGape, "ArduinoPortExpander NOT found at %#02x", address_);
#endif
this->mark_failed();
return;
}
#ifdef APE_BINARY_SENSOR
if (ERROR_OK != this->read_register(APE_CMD_DIGITAL_READ, const_cast<uint8_t *>(this->read_buffer_), 9)) //changed from 3 to 9
{
#ifdef APE_LOGGING
ESP_LOGE(TAGape, "Error reading. Reconfiguring pending.");
#endif
this->status_set_error();
this->configure_timeout_ = millis() + 5000;
return;
}
for (ApeBinarySensor *pin : this->input_pins_)
{
uint8_t pinNo = pin->get_pin();
uint8_t bit = pinNo % 8;
uint8_t value = pinNo < 8 ? this->read_buffer_[0] : pinNo < 16 ? this->read_buffer_[1] : pinNo < 24 ? this->read_buffer_[2] : pinNo < 32 ? this->read_buffer_[3] : pinNo < 40 ? this->read_buffer_[4] : pinNo < 48 ? this->read_buffer_[5] : pinNo < 56 ? this->read_buffer_[6] : pinNo < 64 ? this->read_buffer_[7] : this->read_buffer_[8];
bool ret = value & (1 << bit);
if (this->initial_state_)
pin->publish_initial_state(ret);
else
pin->publish_state(ret);
}
#endif
#ifdef APE_SENSOR
for (ApeAnalogInput *pin : this->analog_pins_)
{
uint8_t pinNo = pin->get_pin();
pin->publish_state(analogRead(pinNo));
}
#endif
this->initial_state_ = false;
}
#ifdef APE_SENSOR
uint16_t analogRead(uint8_t pin)
{
bool ok = (ERROR_OK == this->read_register((uint8_t)(CMD_ANALOG_READ_A0 + pin), const_cast<uint8_t *>(this->read_buffer_), 2, 1));
#ifdef APE_LOGGING
ESP_LOGVV(TAGape, "analog read pin: %d ok: %d byte0: %d byte1: %d", pin, ok, this->read_buffer_[0], this->read_buffer_[1]);
#endif
uint16_t value = this->read_buffer_[0] | ((uint16_t)this->read_buffer_[1] << 8);
return value;
}
#endif
#ifdef APE_BINARY_OUTPUT
output::BinaryOutput *get_binary_output(uint8_t pin)
{
ApeBinaryOutput *output = new ApeBinaryOutput(this, pin);
output_pins_.push_back(output);
return output;
}
#endif
#ifdef APE_BINARY_SENSOR
binary_sensor::BinarySensor *get_binary_sensor(uint8_t pin)
{
ApeBinarySensor *binarySensor = new ApeBinarySensor(this, pin);
input_pins_.push_back(binarySensor);
return binarySensor;
}
#endif
#ifdef APE_SENSOR
sensor::Sensor *get_analog_input(uint8_t pin)
{
ApeAnalogInput *input = new ApeAnalogInput(this, pin);
analog_pins_.push_back(input);
return input;
}
#endif
void write_state(uint8_t pin, bool state, bool setup = false)
{
if (this->configure_timeout_ != 0)
return;
#ifdef APE_LOGGING
ESP_LOGD(TAGape, "Writing %d to pin %d", state, pin);
#endif
this->write_register(state ? APE_CMD_WRITE_DIGITAL_HIGH : APE_CMD_WRITE_DIGITAL_LOW, &pin, 1);
if (setup)
{
App.feed_wdt();
delay(20);
#ifdef APE_LOGGING
ESP_LOGI(TAGape, "Setup output pin %d", pin);
#endif
this->write_register(APE_CMD_SETUP_PIN_OUTPUT, &pin, 1);
}
}
protected:
bool configure_{true};
bool initial_state_{true};
uint8_t read_buffer_[9]{0, 0, 0, 0, 0, 0, 0, 0, 0}; //changed from [3]{0, 0, 0}
unsigned long configure_timeout_{5000};
bool vref_default_{false};
#ifdef APE_BINARY_OUTPUT
std::vector<ApeBinaryOutput *> output_pins_;
#endif
#ifdef APE_BINARY_SENSOR
std::vector<ApeBinarySensor *> input_pins_;
#endif
#ifdef APE_SENSOR
std::vector<ApeAnalogInput *> analog_pins_;
#endif
};
#ifdef APE_BINARY_OUTPUT
void ApeBinaryOutput::write_state(bool state)
{
this->state_ = state;
this->parent_->write_state(this->pin_, state, this->setup_);
this->setup_ = false;
}
#endif
``Hi, I have arduino nano which is using D2, D3...D13 for digital pins. Neither source .h file, nor .ino file let me to compile and use these pins with such numerotation. Only 2-13.
Could you please tell me where or what should I need to change in order to work?
I'm using instructions (first time....) from esphome webpage where is stated this:
ape_binary_output(expander1, 2)
Thanks
In file included from src/main.cpp:50: /config/esphome/replace-espeasy.yaml: In lambda function: /config/esphome/replace-espeasy.yaml:64:44: error: 'D9' was not declared in this scope 64 | return {ape_binary_output(expander1, D9), | ^~ src/arduino_port_expander.h:43:69: note: in definition of macro 'ape_binary_output' 43 | #define ape_binary_output(ape, pin) get_ape(ape)->get_binary_output(pin) | ^~~ /config/esphome/replace-espeasy.yaml:65:42: error: 'D10' was not declared in this scope; did you mean 'B10'? 65 | ape_binary_output(expander1, D10), | ^~~ src/arduino_port_expander.h:43:69: note: in definition of macro 'ape_binary_output' 43 | #define ape_binary_output(ape, pin) get_ape(ape)->get_binary_output(pin) | ^~~ /config/esphome/replace-espeasy.yaml:66:42: error: 'D11' was not declared in this scope; did you mean 'B11'? 66 | ape_binary_output(expander1, D11), | ^~~ src/arduino_port_expander.h:43:69: note: in definition of macro 'ape_binary_output' 43 | #define ape_binary_output(ape, pin) get_ape(ape)->get_binary_output(pin) | ^~~ /config/esphome/replace-espeasy.yaml:67:42: error: 'D12' was not declared in this scope 67 | ape_binary_output(expander1, D12)}; | ^~~ src/arduino_port_expander.h:43:69: note: in definition of macro 'ape_binary_output' 43 | #define ape_binary_output(ape, pin) get_ape(ape)->get_binary_output(pin) | ^~~ /config/esphome/replace-espeasy.yaml:67:46: error: could not convert '{<expression error>, <expression error>, <expression error>, <expression error>}' from '<brace-enclosed initializer list>' to 'std::vector<esphome::output::BinaryOutput*>' 67 | ape_binary_output(expander1, D12)}; | ^ | | | <brace-enclosed initializer list> *** [/data/replace-espeasy/.pioenvs/replace-espeasy/src/main.cpp.o] Error 1
Changed board to esp12e and added another power source to arduino. No need to use Dx pins, it works like in documentation.
So is no issue here :)
Is there a way to get this to support a Rotary Encoder, etc?
Something like this:
sensors:
- platform: custom
lambda: |-
return {ape_sensor(expander1, 2),
ape_sensor(expander1, 3),
ape_sensor(expander1, 4)
};
sensor:
# Rotary Encoder
- platform: rotary_encoder
name: "Rotary Encoder"
pin_a: encoderApin
pin_b: encoderBpin
# DHT22
- platform: dht
pin: dht22pin
temperature:
name: "Living Room Temperature"
humidity:
name: "Living Room Humidity"
update_interval: 60s
@NonaSuomy Did you ever figure out how to get a rotary encoder to work?
No I have not, what pin are you using, analog or digital?
@kc9ryt I confirmed with @glmnet and they said it is not currently possible to utilize this library like that as it has no way to link up the encoder stuff in ESPHome with the Arduino port expander. You would have to modify the code base to allow it to accept these functions.
I found another Arduino library that allows you to use Rotary Encoders over I2C but in its current state can't just be utilized like this library by including it and would have to be modified to be properly compatible. I ask the maintainer if it was possible to do something like this. They said they may be able to look into it unfortunately their health faltered and couldn't look into it.
This seems to no longer work starting with ESPHome 2021.10.x. Apparently, as suggested by folks smarter than me, due to core changes. "For example the I2CComponent is used in there, which has been changed into an I2CBus. So that .h file would need a partial rewrite to make it compatible with 2021.10.0."