Giter Club home page Giter Club logo

esphome-arduino-port-expander's People

Contributors

thebradleysanders avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

esphome-arduino-port-expander's Issues

W32-ETH01 with Mega2560 gets stuck periodically

Hello,
First thing thanks for great sollution working well until it stops.
I use ESPHome an ESP32 based board with LAN connection. Pins 12 and 14 are used for SDA and SCL, connected to Arduino mega pins 20 and 21, with standard DuPont cables (12-15cm).
Now after ~12-30hours everything stops working, ESP gets to stuck state where it needs to have I2C lane disconnected and restarted before starts working again.
Both Arduino and ESP are powered from 5v supply.

Relays not activating

hello im not sure if you can help but im only amateur at best with coding. attached i will show the coding i used

Problem (if i run the blink sketch with the relays on the arduino they work) did this to confirm boards are functioning correctly
when i connect everything up and run it through home assistant (esphome) it shows i2c has been found, and arduino serial logger show pin 2 pulled high, pin 2 pulled low when switch is toggled, however the relay does not do anything.
if i connect a voltage meter whilst all is still plugged in i get 4.83 volts and when the switch is toggled to on i get 0.10 volts

attached is both your code and the esphome code (example i am using to test before changing it)

Edit: i should also mention, if i connect a blue led (all i have) between ground and pin 2 it toggles with everything connected as expected.
power supply is 12v 1amp connected to arduino for testing purposes. As show in diagram at bottom arduino is powering the esp8266 (even separately powered i have the same issue)

Your code

/*
Ports:
  0 0 .. 13 13 .. 53 53
  Uno: A0: 14, A1: 15, A2: 16, A3: 17: A4: 18: A5: 19: A6: 20, A7: 21
  Mega: A0: 54, A1: 55, A2: 56, A3: 57: A4: 58: A5: 59: A6: 60, A7: 61...
  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 DEBUG_READ // more advanced debuging

#define I2C_ADDRESS 8 //i2c starts at pin 8

void onRequest();
void onReceive(int);

void setup()
{
#ifdef DEBUG
  Serial.begin(115200);
  Serial.println(F("Init "));
#endif

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    analogReference(INTERNAL1V1);
#endif
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
    analogReference(INTERNAL);
#endif

  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[9];
volatile byte len = 1;

#define DIGITAL_READ(b, pin, mask) \
  if (digitalRead(pin))            \
    buffer[b] |= mask;

void readDigital()
{
  len = 9;
  buffer[0] = 0;
  buffer[1] = 0;
  buffer[2] = 0;
  buffer[3] = 0;
  buffer[4] = 0;
  buffer[5] = 0;
  buffer[6] = 0;
  buffer[7] = 0;
  buffer[8] = 0;
  
  DIGITAL_READ(0, 0, 1); //0
  DIGITAL_READ(0, 1, 2); //1
  DIGITAL_READ(0, 2, 4); //2
  DIGITAL_READ(0, 3, 8); //3
  DIGITAL_READ(0, 4, 16); //4
  DIGITAL_READ(0, 5, 32); //5
  DIGITAL_READ(0, 6, 64); //6
  DIGITAL_READ(0, 7, 128); //7

  DIGITAL_READ(1, 8, 1); //8
  DIGITAL_READ(1, 9, 2); //9
  DIGITAL_READ(1, 10, 4); //10
  DIGITAL_READ(1, 11, 8); //11
  DIGITAL_READ(1, 12, 16); //12
  DIGITAL_READ(1, 13, 32); //13

//Arduino Mega Boards
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  DIGITAL_READ(1, 14, 64); //14
  DIGITAL_READ(1, 15, 128); //15

  DIGITAL_READ(2, 16, 1); //16
  DIGITAL_READ(2, 17, 2); //17
  DIGITAL_READ(2, 18, 4); //18
  DIGITAL_READ(2, 19, 8); //19
  DIGITAL_READ(2, 19, 16); //20 Not avaliable on Arduino Mega, i2c pin.
  DIGITAL_READ(2, 19, 32); //21 Not avaliable on Arduino Mega, i2c pin.
  DIGITAL_READ(2, 22, 64); //22
  DIGITAL_READ(2, 23, 128); //23

  DIGITAL_READ(3, 24, 1); //24
  DIGITAL_READ(3, 25, 2); //25
  DIGITAL_READ(3, 26, 4); //26
  DIGITAL_READ(3, 27, 8); //27
  DIGITAL_READ(3, 28, 16); //28
  DIGITAL_READ(3, 29, 32); //29
  DIGITAL_READ(3, 30, 64); //30
  DIGITAL_READ(3, 31, 128); //31

  DIGITAL_READ(4, 32, 1); //32
  DIGITAL_READ(4, 33, 2); //33
  DIGITAL_READ(4, 34, 4); //34
  DIGITAL_READ(4, 35, 8); //35
  DIGITAL_READ(4, 36, 16); //36
  DIGITAL_READ(4, 37, 32); //37
  DIGITAL_READ(4, 38, 64); //38
  DIGITAL_READ(4, 39, 128); //39

  DIGITAL_READ(5, 40, 1); //40
  DIGITAL_READ(5, 41, 2); //41
  DIGITAL_READ(5, 42, 4); //42
  DIGITAL_READ(5, 43, 8); //43
  DIGITAL_READ(5, 44, 16); //44
  DIGITAL_READ(5, 45, 32); //45
  DIGITAL_READ(5, 46, 64); //46
  DIGITAL_READ(5, 47, 128); //47

  DIGITAL_READ(6, 48, 1); //48
  DIGITAL_READ(6, 49, 2); //49
  DIGITAL_READ(6, 50, 4); //50
  DIGITAL_READ(6, 51, 8); //51
  DIGITAL_READ(6, 52, 16); //52
  DIGITAL_READ(6, 53, 32); //53
  DIGITAL_READ(6, A0, 64); //54
  DIGITAL_READ(6, A1, 128); //55

  DIGITAL_READ(7, A2, 1); //56
  DIGITAL_READ(7, A3, 2); //57
  DIGITAL_READ(7, A4, 4); //58
  DIGITAL_READ(7, A5, 8); //59
  DIGITAL_READ(7, A6, 16); //60
  DIGITAL_READ(7, A7, 32); //61
  DIGITAL_READ(7, A8, 64); //62
  DIGITAL_READ(7, A9, 128); //63

  DIGITAL_READ(8, A10, 1); //64
  DIGITAL_READ(8, A11, 2); //65
  DIGITAL_READ(8, A12, 4); //66
  DIGITAL_READ(8, A13, 8); //67
  DIGITAL_READ(8, A14, 16); //68
  DIGITAL_READ(8, A15, 32); //69
#endif

// Arduino Uno Boards
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
  DIGITAL_READ(1, A0, 64); //14
  DIGITAL_READ(1, A1, 128); //15

  DIGITAL_READ(2, A2, 1); //16
  DIGITAL_READ(2, A3, 2); //17
  //DIGITAL_READ(2, A4, 4); //Not avaliable on Arduino Uno, i2c pin.
  //DIGITAL_READ(2, A5, 8); //Not avaliable on Arduino Uno, i2c pin.
  DIGITAL_READ(2, A6, 16); //20
  DIGITAL_READ(2, A7, 32); //21
#endif

// DIGITAL READ not supports on A3 .. A7 on Arduino Uno
#ifdef DEBUG_READ
  Serial.print(F("Read 9 bytes: "));
  Serial.print(buffer[0]);
  Serial.print(' ');
  Serial.print(buffer[1]);
  Serial.print(' ');
  Serial.println(buffer[2]);
  Serial.print(' ');
  Serial.println(buffer[3]);
  Serial.print(' ');
  Serial.println(buffer[4]);
  Serial.print(' ');
  Serial.println(buffer[5]);
  Serial.print(' ');
  Serial.println(buffer[6]);
  Serial.print(' ');
  Serial.println(buffer[7]);
  Serial.print(' ');
  Serial.println(buffer[8]);
#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 A14
// A4 and A5 on Arduino Uno are not supported due to I2C
#define CMD_ANALOG_READ_A0 0b1000 // 0x8
// ....
#define CMD_ANALOG_READ_A14 0b10000 //16

#define CMD_SETUP_ANALOG_INTERNAL 0x10
#define CMD_SETUP_ANALOG_DEFAULT 0x12

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_A14)
  {
    readAnalog(cmd & 0b1110);
    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:

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    analogReference(INTERNAL1V1);
#endif
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
    analogReference(INTERNAL);
#endif
#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;
  }
}

### The Esphome Example Config

esphome:
  name: pool-management-system
  friendly_name: Pool Management System
  includes:
  - arduino_port_expander.h

esp8266:
  board: nodemcu


# Enable Home Assistant API
api:
  encryption:
    key: **"REMOVED"**

ota:
  password: **"REMOVED"**

wifi:
  ssid: **"REMOVED"**
  password: **"REMOVED"**

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Pool-Management-System"
    password: **"REMOVED"**

# define i2c device
# for an ESP8266 SDA is D2 and goes to Arduino's A4
#                SCL is D1 and goes to Arduino's A5
i2c:
  id: i2c_component

logger:
  level: DEBUG

# define the port expander hub, here we define one with id 'expander1',
# but you can define many
custom_component:
  - id: expander1
    lambda: |-
      auto expander = new ArduinoPortExpander(i2c_component, 0x08, true);
      return {expander};

# define binary outputs, here we have 4, as the relays are inverse logic
# (a path to ground turns the relay ON), we defined the inverted: true
# option of ESPHome outputs.
output:
- platform: custom
  type: binary
  lambda: |-
    return {ape_binary_output(expander1, 2),
            ape_binary_output(expander1, 3),
            ape_binary_output(expander1, 4),
            ape_binary_output(expander1, 5)};

  outputs:
    - id: relay_1
      inverted: true
    - id: relay_2
      inverted: true
    - id: relay_3
      inverted: true
    - id: relay_4
      inverted: true

# connect lights to the first 2 relays
light:
  - platform: binary
    id: ceiling_light
    name: Ceiling light
    output: relay_1
  - platform: binary
    id: room_light
    name: Living room light
    output: relay_2

# connect a fan to the third relay
fan:
- platform: binary
  id: ceiling_fan
  output: relay_3
  name: Ceiling fan

# connect a pump to the 4th relay
switch:
  - platform: output
    name: Tank pump
    id: tank_pump
    output: relay_4


# define binary sensors, use the Arduino PIN number for digital pins and
# for analog use 14 for A0, 15 for A1 and so on...
binary_sensor:
  - platform: custom
    lambda: |-
      return {ape_binary_sensor(expander1, 7),
              ape_binary_sensor(expander1, 8),
              ape_binary_sensor(expander1, 9),
              ape_binary_sensor(expander1, 10),
              ape_binary_sensor(expander1, 14) // 14 = A0
              };

    binary_sensors:
      - id: push_button1
        internal: true # don't show on HA
        on_press:
          - light.toggle: ceiling_light
      - id: push_button2
        internal: true # don't show on HA
        on_press:
          - light.toggle: room_light
      - id: pir_sensor
        name: Living PIR
        device_class: motion
      - id: window_reed_switch
        name: Living Window
        device_class: window
      - id: garage_door
        name: Garage garage
        device_class: garage_door

# define analog sensors
sensor:
  - platform: custom
    lambda: |-
      return {ape_analog_input(expander1, 1),  // 1 = A1
              ape_analog_input(expander1, 2)};
    sensors:
      - name: LM35 Living room temperature
        id: lm35_temp
        filters:
          # update every 60s
          - throttle: 60s
          # LM35 outputs 0.01v per ºC, and 1023 means 3.3 volts
          - lambda: return x * 330.0 / 1023.0;
      - name: Analog A2
        id: analog_a2
        filters:
          - throttle: 2s

Crude sketch of my circuit

Arduino Port Expand Relays

Not working with Mega2560

Hi Bradley, i have just tried to upload .ino and .h into my Mega2560 + Nodemcu and it is not flying together. Is the current commit the working one?

Adding a text sensor option (Dev workflow)

Hey thanks for this update, it is great. I got My Mega 2560 up and running quickly. I have a few sensors like temperature that the data is pre formatted and some arbitrary data that I'd like to send. I started to add in an ape_text_sensor option but I'm using VS code and cant seem to get the include paths setup to not throw a bunch of false errors on things like "using namespace esphome". I cloned the esphome repo and set an include path to the root of the repo recursively but that's not been working for me. What's your dev setup like to work on this? Is there a way I can contribute or customize for my own purpose that I can get some proper intellisense?

Problem with adc ports mega

Hello, i want to use the adc ports from the mega, but it looks like there is someting wrong.
The ports are not read? I mean it looks like it is using the wrong pins.
I want to use Channel 0 to 15 but there is no reactions to the connected sensors.
The sensor send 3,27v (potentiometer). So what needs to change so adc0 is pin 54?
When i connect the sensor to adc 8 on the atmega it registers at adc0 in esphome?
Thank you for your time and effort
Regards marco

Help converting atmega32u4

Hi @thebradleysanders
I see you converted the code for the mega any idea how to convert it for the 32u4?

https://github.com/thebradleysanders/ESPHome-Arduino-Port-Expander/blob/main/arduino_port_expander.h#L34

How do you get the right binary values for the pins?

01 (INT.6/AIN0) PE6
02 UVcc
03 D
04 D+
05 UGnd
06 UCap
07 VBus
08 (SS/PCINT0) PB0
09 (PCINT1/SCLK) PB1
10 (PDI/PCINT2/MOSI) PB2
11 (PDO/PCINT3/MISO) PB3
12 (PCINT7/OC0A/OC1C/RTS) PB7
13 RESET
14 VCC
15 GND
16 XTAL2
17 XTAL1
*18 (OC0B/SCL/INT0) PD0
*19 (SDA/INT1) PD1
20 (RXD1/INT2) PD2
21 (TXD1/INT3) PD3
22 (XCK1/CTS) PD5
23 GND
24 AVCC
25 PD4 (ICP1/ADC8)
26 PD6 (T1/OC4D/ADC9)
27 PD7 (T0/OC4D/ADC10)
28 PB4 (PCINT4/ADC11)
29 PB5 (PCINT5/OC1A/OC4B/ADC12)
30 PB6 (PCINT6/OC1B/OC4B/ADC13)
31 PC6 (OC3A/OC4A)
32 PC7 (ICP3/CLK0/OC4A)
33 PE2 (HWB)
34 VCC
35 GND


Analog
32u4                         324p                                Not defined
36 PF7 (ADC7/TDI)   22 ADC7 
37 PF6 (ADC6/TDO) 19 ADC6 
38 PF5 (ADC5/TMS) 28 PC5 (ADC5/SCL/PCINT13)    26 PC3 (ADC3/PCINT11)
39 PF4 (ADC4/TCK)  27 PC4 (ADC4/SDA/PCINT12)   25 PC2 (ADC2/PCINT10)
40 PF1 (ADC1)          22 PC1 (ADC1/PCINT9)
41 PF0 (ADC0)          23 PC0 (ADC0/PCINT8)


42 AREF
43 GND
44 AVCC

Thank you for any help.

Not working with latest ESPHOME versions

Hi,
I was searching for a version if arduinoportexpander for Arduino Mega and found your code.

Unfortunately it was not working with the latest version of Esphome. I've seen the recently the code from glmnet was updated due to changes in the ESPHOME core.
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 glmnet 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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.