Let me first say that I’m not coding is not my day job so I could use some help cleaning this up. However, the code is working as is for using the DS2413 as a dual switch. However, it’s kludgy because I couldn’t figure out how to create a custom component with multiple switches which is all kinds of inefficient. It scans the bus twice on startup, I have duplicative but otherwise equal functions, etc. I’ll post what I have and if anyone wants to help me clean it up I would be much appreciative. The limitations of the current state of code as I can think of are:
- only supports a single DS2413 device on the oneWire bus
- no restore on boot, you set default boot states with bool variables near the top
- scans the bus twice on setup()
- switch output mode only, no support yet for using as an input
- on bus scan, the address is printed incorrectly
To use, create a file called “custom_component_DS2413.h” with the contents shown below and copy it to your esphome yaml location. Also grab the OneWire.cpp and OneWire.h files and put them in the same directory. Finally, create an esphome project using the yaml code below. Adjust the top part to your board, names can be whatever you want.
OneWire files
With that all out of the way, here it is working:
relevant yaml:
esphome:
name: ${project_name}
platform: ESP8266
board: d1_mini
includes:
- custom_component_DS2413.h
libraries:
- "OneWire"
switch:
- platform: custom
lambda: |-
auto sw01 = new DS2413_1();
App.register_component(sw01);
return {sw01};
switches:
- id: switch_01
name: "Switch 1"
- platform: custom
lambda: |-
auto sw02 = new DS2413_2();
App.register_component(sw02);
return {sw02};
switches:
- id: switch_02
name: "Switch 2"
custom_component_DS2413.h:
#pragma once
#include "esphome.h"
#include "OneWire.h"
bool inverted = true; // invert output
bool sw1 = false; // set default boot state
bool sw2 = false; // set default boot state
#define DS2413_ONEWIRE_PIN 0 // gpio0 = d3
#define DS2413_FAMILY_ID 0x3A
#define DS2413_ACCESS_READ 0xF5
#define DS2413_ACCESS_WRITE 0x5A
#define DS2413_ACK_SUCCESS 0xAA
#define DS2413_ACK_ERROR 0xFF
#define TAG "dallas"
class DS2413_1 : public Component, public Switch {
public:
OneWire oneWire; // initiate component
uint8_t address[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
DS2413_1():oneWire(DS2413_ONEWIRE_PIN) {} // constructor
void printBytes(uint8_t* addr, uint8_t count) {
for (uint8_t i = 0; i < count; i++)
{
ESP_LOGD(TAG, "%i:", addr[i]); // working but needs conversion to hex and a string buffer
}
}
void setup() override {
ESP_LOGD(TAG, "Looking for a DS2413 on the bus...");
oneWire.reset_search();
delay(250);
if (!oneWire.search(address))
{
printBytes(address, 8);
ESP_LOGD(TAG, "No device found on the bus!");
oneWire.reset_search();
while(1);
}
/* Check the CRC in the device address */
if (OneWire::crc8(address, 7) != address[7])
{
ESP_LOGD(TAG, "Invalid CRC!");
while(1);
}
/* Make sure we have a DS2413 */
if (address[0] != DS2413_FAMILY_ID)
{
printBytes(address, 8);
ESP_LOGD(TAG, " is not a DS2413!");
while(1);
}
ESP_LOGD(TAG, "Found a DS2413: ");
printBytes(address, 8);
write_state(sw1);
}
bool write(uint8_t state)
{
uint8_t ack = 0;
state |= 0xFC; /* Top six bits must '1' */
oneWire.reset();
oneWire.select(address);
oneWire.write(DS2413_ACCESS_WRITE);
oneWire.write(state);
oneWire.write(~state); /* Invert data and resend */
ack = oneWire.read(); /* 0xAA=success, 0xFF=failure */
if (ack == DS2413_ACK_SUCCESS)
{
oneWire.read(); /* Read the status byte */
}
oneWire.reset();
return (ack == DS2413_ACK_SUCCESS ? true : false);
}
void write_state(bool state) override
{
sw1 = state;
bool ok = false;
ESP_LOGD(TAG, "Writing state of: %i", sw1);
if (sw2 && sw1) {
ok = (inverted) ? write (0x00) : write(0x03);
} else if (sw2 && !sw1) {
ok = (inverted) ? write (0x01) : write(0x02);
} else if (!sw2 && sw1) {
ok = (inverted) ? write (0x02) : write(0x01);
} else {
ok = (inverted) ? write (0x03) : write(0x00);
}
(ok) ? publish_state(sw1) : ESP_LOGD("custom", "Wire failed");
} // write_state
}; // class
class DS2413_2 : public Component, public Switch {
public:
OneWire oneWire; // initiate component
uint8_t address[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
DS2413_2():oneWire(DS2413_ONEWIRE_PIN) {} // constructor
void printBytes(uint8_t* addr, uint8_t count) {
for (uint8_t i = 0; i < count; i++)
{
ESP_LOGD(TAG, "%i:", addr[i]); // working but needs conversion to hex and a buffer
}
}
void setup() override {
ESP_LOGD(TAG, "Looking for a DS2413 on the bus...");
oneWire.reset_search();
delay(250);
if (!oneWire.search(address))
{
printBytes(address, 8);
ESP_LOGD(TAG, "No device found on the bus!");
oneWire.reset_search();
while(1);
}
/* Check the CRC in the device address */
if (OneWire::crc8(address, 7) != address[7])
{
ESP_LOGD(TAG, "Invalid CRC!");
while(1);
}
/* Make sure we have a DS2413 */
if (address[0] != DS2413_FAMILY_ID)
{
printBytes(address, 8);
ESP_LOGD(TAG, " is not a DS2413!");
while(1);
}
ESP_LOGD(TAG, "Found a DS2413: ");
printBytes(address, 8);
write_state(sw2);
}
bool write(uint8_t state)
{
uint8_t ack = 0;
state |= 0xFC; /* Top six bits must '1' */
oneWire.reset();
oneWire.select(address);
oneWire.write(DS2413_ACCESS_WRITE);
oneWire.write(state);
oneWire.write(~state); /* Invert data and resend */
ack = oneWire.read(); /* 0xAA=success, 0xFF=failure */
if (ack == DS2413_ACK_SUCCESS)
{
oneWire.read(); /* Read the status byte */
}
oneWire.reset();
return (ack == DS2413_ACK_SUCCESS ? true : false);
}
void write_state(bool state) override
{
sw2 = state;
bool ok = false;
ESP_LOGD(TAG, "Writing state of: %i", sw2);
if (sw2 && sw1) {
ok = (inverted) ? write (0x00) : write(0x03);
} else if (sw2 && !sw1) {
ok = (inverted) ? write (0x01) : write(0x02);
} else if (!sw2 && sw1) {
ok = (inverted) ? write (0x02) : write(0x01);
} else {
ok = (inverted) ? write (0x03) : write(0x00);
}
(ok) ? publish_state(sw2) : ESP_LOGD("custom", "Wire failed");
} // write_state
}; // class
All the best,
-J