Skip to content

Commit

Permalink
New InputPinArrayNode for simple IO + doc improvements
Browse files Browse the repository at this point in the history
+ InputPinArrayNode can be used to define a vector of GPIOs that are
configured as INPUT_PULLUP and announced as array of Contacts.
+ created doxyfile for doc generation with doxygen
+ added some doxygen-style doc-strings
+ small refactoring of RelaisNode
  • Loading branch information
euphi committed Apr 12, 2018
1 parent 2f66c2a commit ffb13d0
Show file tree
Hide file tree
Showing 7 changed files with 2,638 additions and 33 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
/.project
/.settings
src/main.cpp
/html/
/latex/
2,494 changes: 2,494 additions & 0 deletions ESP_Heizungscontroller.doxyfile

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "HomieNodeCollection",
"version": "0.9.1",
"version": "0.9.2",
"keywords": "Homie, sensor, temperature, display",
"description": "Collection of Node implementations for the Homie-ESP8266 library.",
"repository": {
Expand Down
46 changes: 46 additions & 0 deletions src/InputPinArrayNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* InputPinArrayNode.cpp
*
* Created on: 09.04.2018
* Author: ian
*/

#include <InputPinArrayNode.h>

InputPinArrayNode::InputPinArrayNode(std::vector<uint8_t> pins, InputPinChangeEventHandler& cb):
HomieNode("Input", "Contact"),
inputPins(pins),
storedPins(pins.size()),
callback(cb) {
advertiseRange("pin", 0, inputPins.size()-1);
}

void InputPinArrayNode::setup() {
for (uint8_t pin : inputPins) {
pinMode(pin, INPUT_PULLUP);
}
}

void InputPinArrayNode::loop() {
uint8_t idx = 0;
for (uint8_t pin : inputPins) {
bool curState = digitalRead(pin);
bool oldState = storedPins[idx];
if (curState != oldState) {
setProperty("pin").setRange(idx).setRetained(true).send(curState ? "OPEN":"CLOSED");
storedPins[idx] = curState;
callback(idx, curState);
}
++idx;
}
}

void InputPinArrayNode::onReadyToOperate() {
uint8_t idx = 0;
for (uint8_t pin : inputPins) {
bool curState = digitalRead(pin);
storedPins[idx] = curState;
setProperty("pin").setRange(idx).setRetained(true).send(curState ? "OPEN":"CLOSED");
idx++;
}
}
33 changes: 33 additions & 0 deletions src/InputPinArrayNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* InputPinArrayNode.h
*
* Created on: 09.04.2018
* Author: ian
*/

#ifndef SRC_INPUTPINARRAYNODE_H_
#define SRC_INPUTPINARRAYNODE_H_

#include <HomieNode.hpp>



class InputPinArrayNode: public HomieNode {


public:
typedef std::function<bool(uint8_t idx, bool state)> InputPinChangeEventHandler;
InputPinArrayNode(std::vector<uint8_t> pins, InputPinChangeEventHandler& cb);

protected:
virtual void setup() override;
virtual void loop() override;
virtual void onReadyToOperate() override;

private:
std::vector<uint8_t> inputPins;
std::vector<bool> storedPins;
InputPinChangeEventHandler & callback;
};

#endif /* SRC_INPUTPINARRAYNODE_H_ */
91 changes: 59 additions & 32 deletions src/RelaisNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,18 @@
#include <LoggerNode.h>
#include <Homie.hpp>

/** Constructor. Use it to configure the inputs and outputs
* @param defaults initial default value
* @param invert If a bit is set, the corresponding IO is inverted (OUTPUT only, also inverts initial value)
* @param inputmask: If a bit is set, the corresponding IO is configured as INPUT_PULLUP, if not, as OUTPUT
*/
RelaisNode::RelaisNode(uint16_t defaults, uint16_t invert, uint16_t inputmask) :
HomieNode("Relais", "switch16"),
relais_bitset((defaults^invert) | inputmask),
invert_bitset(invert),
input_mask(inputmask),
input_data(0x0000),
updateMaskLoop(0x0000),
io(0x20, false) {
for (uint_fast8_t i = 0 ; i < 16 ; i++) {
bool in = ((input_mask & (1 << i)) != 0);
Expand All @@ -24,35 +30,71 @@ RelaisNode::RelaisNode(uint16_t defaults, uint16_t invert, uint16_t inputmask) :
advertiseRange("in",1,16).settable();
}

/** only thing to do in setup(): Initial write of output values to PCF
*
*/
void RelaisNode::setup() {
updateRelais(0); // write to PCF only
}

/** only thing to do in onReadyToOperate(): Send initial values to Homie MQTT
*
*/
void RelaisNode::onReadyToOperate() {
LN.log("RelaisNode", LoggerNode::DEBUG, "Ready");
delay(200);
RelaisNode::updateRelais(0xFFFF);
}

void RelaisNode::loop() {
static uint_fast8_t count = 0;
if (!(++count % 8)==0) return; // read I2C on every 8th cycle only
/** Read input from IO device
* Checks for difference in the selected bits (every bit set in field input_mask).
* In case of difference, the new property (ranged index) of the RelaisNode is send over MQTT */
void RelaisNode::readInputs() {
uint16_t input = io.read16();
uint16_t diff = ((input ^ input_data) & input_mask);
if (diff == 0) return;
for (uint_fast8_t i = 0 ; i<16; i++) {
if ((diff & (1 << i)) != 0)
{
for (uint_fast8_t i = 0; i < 16; i++) {
if ((diff & (1 << i)) != 0) {
bool on = (input_data & (1 << i)) != 0;
bool inverted = (invert_bitset & (1 << i)) != 0;
LN.logf("RN::loop", LoggerNode::INFO, "Input %d changed to %c%s, new: %x, old: %x, diff: %x",
i, inverted ? '~':' ', on ? "On" : "Off", input, input_data, diff);
setProperty("in").setRange(i+1).send(on ^ inverted ? "ON": "OFF");
LN.logf("RN::loop", LoggerNode::INFO,
"Input %d changed to %c%s, new: %x, old: %x, diff: %x", i,
inverted ? '~' : ' ', on ? "On" : "Off", input, input_data,
diff);
setProperty("in").setRange(i + 1).send(
on ^ inverted ? "ON" : "OFF");
}
}
input_data = input;
}

/** loop() is called every cycle from Homie
* Overrides the HomieNode::loop() method. Every 8th cycle it checks the inputs for changes.
* Furthermore it updates the outputs if a change has occured.
* To do the actual change of output within the loop() function is necessary
* because the handleInput() method is running in the network task of the NON-OS SDK
* due to the use of async IO. If a write would occur during the handleInput there
* is a race condition between writing the output and reading the input that may disturb
* the I2C communication or may give false readings and/or writings.
*
* See also https://euphi.github.io/2018/03/31/ArduinoESP8266-multipleTasks.html
*
*/
void RelaisNode::loop() {
static uint_fast8_t count = 0;
if ((++count % 8)==0) readInputs(); // read I2C on every 8th cycle only
if (updateMaskLoop) {
updateRelais(updateMaskLoop);
updateMaskLoop = 0x0000;
}

}

/** handleInput() handles the received MQTT messages from Homie
*
* The bit to change is
* The property is not checked (but this is done by homie when evaluating the range)
*
*/
bool RelaisNode::handleInput(const String &property, const HomieRange& range, const String &value) {
int16_t id = range.index;
if (id <= 0 || id > 16) {
Expand All @@ -72,31 +114,16 @@ bool RelaisNode::handleInput(const String &property, const HomieRange& range, c
} else {
relais_bitset &= ~selected_bit;
}
updateRelais(selected_bit);
updateMaskLoop |= selected_bit;
return true;
}

//
//void RelaisNode::drawFrame(OLEDDisplay& display, OLEDDisplayUiState& state, int16_t x, int16_t y) {
// bool blink = ((millis() >> 7) % 2) != 0;
// display.setFont(ArialMT_Plain_16);
// display.drawString(0+x,16,"Relais");
// for (uint_fast8_t i=0; i<8;i++) {
// int16_t xpos = (i*8)+4;
// int16_t ypos = 40;
// if (((i + 1) == encoder.state()) && blink) continue;
// bool on = (relais_bitset & (1 << i)) != 0;
// display.drawRect(xpos,ypos,on?6:5,on?6:5);
// if (on) {
// display.drawRect(xpos+1,ypos+1,4,4);
// display.drawRect(xpos+2,ypos+2,2,2);
// }
// }
// display.drawHorizontalLine(0,60,128);
//}



/** helper method to update output state
* @param updateMask bits that needs to be updated on MQTT
*
* This method write all data to the I2C device.
* Furthermore it checks which bits should be updated on Homie MQTT and sends their state
*/
void RelaisNode::updateRelais(uint16_t updateMask) {
static uint16_t last = relais_bitset;
LN.logf("RelaisNode::updateRelais()", LoggerNode::DEBUG, "Value: %x (Update: %x)", relais_bitset, updateMask);
Expand Down
3 changes: 3 additions & 0 deletions src/RelaisNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,15 @@ class RelaisNode : public HomieNode {

private:
void updateRelais(uint16_t updateMask=0xFFFF);
void readInputs();

uint16_t relais_bitset; // stores actual value
uint16_t invert_bitset; // If bit is set, value written to PCF8575 will be inverted
uint16_t input_mask; // If bit is set, related pin will be configured as (quasi-)input
uint16_t input_data;

uint16_t updateMaskLoop;

PCF8575 io;

};
Expand Down

0 comments on commit ffb13d0

Please sign in to comment.