Initial commit
This commit is contained in:
		
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | .pio | ||||||
|  | .vscode/.browse.c_cpp.db* | ||||||
|  | .vscode/c_cpp_properties.json | ||||||
|  | .vscode/launch.json | ||||||
|  | .vscode/ipch | ||||||
							
								
								
									
										7
									
								
								.vscode/extensions.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.vscode/extensions.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | { | ||||||
|  |     // See http://go.microsoft.com/fwlink/?LinkId=827846 | ||||||
|  |     // for the documentation about the extensions.json format | ||||||
|  |     "recommendations": [ | ||||||
|  |         "platformio.platformio-ide" | ||||||
|  |     ] | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | # DoorBell-MQTT-Gateway | ||||||
|  |  | ||||||
|  | Based on | ||||||
|  |  | ||||||
|  | - Arduino Uno | ||||||
|  | - Ethernet interface | ||||||
|  |  | ||||||
|  | Watchout for GPIO changes as triggers for | ||||||
|  |  | ||||||
|  | - door bell input | ||||||
|  | - post box observer (post entry) | ||||||
|  | - post box observer (takeout posts) | ||||||
|  | - ... | ||||||
							
								
								
									
										39
									
								
								include/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								include/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  |  | ||||||
|  | This directory is intended for project header files. | ||||||
|  |  | ||||||
|  | A header file is a file containing C declarations and macro definitions | ||||||
|  | to be shared between several project source files. You request the use of a | ||||||
|  | header file in your project source file (C, C++, etc) located in `src` folder | ||||||
|  | by including it, with the C preprocessing directive `#include'. | ||||||
|  |  | ||||||
|  | ```src/main.c | ||||||
|  |  | ||||||
|  | #include "header.h" | ||||||
|  |  | ||||||
|  | int main (void) | ||||||
|  | { | ||||||
|  |  ... | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Including a header file produces the same results as copying the header file | ||||||
|  | into each source file that needs it. Such copying would be time-consuming | ||||||
|  | and error-prone. With a header file, the related declarations appear | ||||||
|  | in only one place. If they need to be changed, they can be changed in one | ||||||
|  | place, and programs that include the header file will automatically use the | ||||||
|  | new version when next recompiled. The header file eliminates the labor of | ||||||
|  | finding and changing all the copies as well as the risk that a failure to | ||||||
|  | find one copy will result in inconsistencies within a program. | ||||||
|  |  | ||||||
|  | In C, the usual convention is to give header files names that end with `.h'. | ||||||
|  | It is most portable to use only letters, digits, dashes, and underscores in | ||||||
|  | header file names, and at most one dot. | ||||||
|  |  | ||||||
|  | Read more about using header files in official GCC documentation: | ||||||
|  |  | ||||||
|  | * Include Syntax | ||||||
|  | * Include Operation | ||||||
|  | * Once-Only Headers | ||||||
|  | * Computed Includes | ||||||
|  |  | ||||||
|  | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html | ||||||
							
								
								
									
										46
									
								
								lib/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								lib/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  |  | ||||||
|  | This directory is intended for project specific (private) libraries. | ||||||
|  | PlatformIO will compile them to static libraries and link into executable file. | ||||||
|  |  | ||||||
|  | The source code of each library should be placed in a an own separate directory | ||||||
|  | ("lib/your_library_name/[here are source files]"). | ||||||
|  |  | ||||||
|  | For example, see a structure of the following two libraries `Foo` and `Bar`: | ||||||
|  |  | ||||||
|  | |--lib | ||||||
|  | |  | | ||||||
|  | |  |--Bar | ||||||
|  | |  |  |--docs | ||||||
|  | |  |  |--examples | ||||||
|  | |  |  |--src | ||||||
|  | |  |     |- Bar.c | ||||||
|  | |  |     |- Bar.h | ||||||
|  | |  |  |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html | ||||||
|  | |  | | ||||||
|  | |  |--Foo | ||||||
|  | |  |  |- Foo.c | ||||||
|  | |  |  |- Foo.h | ||||||
|  | |  | | ||||||
|  | |  |- README --> THIS FILE | ||||||
|  | | | ||||||
|  | |- platformio.ini | ||||||
|  | |--src | ||||||
|  |    |- main.c | ||||||
|  |  | ||||||
|  | and a contents of `src/main.c`: | ||||||
|  | ``` | ||||||
|  | #include <Foo.h> | ||||||
|  | #include <Bar.h> | ||||||
|  |  | ||||||
|  | int main (void) | ||||||
|  | { | ||||||
|  |   ... | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | PlatformIO Library Dependency Finder will find automatically dependent | ||||||
|  | libraries scanning project source files. | ||||||
|  |  | ||||||
|  | More information about PlatformIO Library Dependency Finder | ||||||
|  | - https://docs.platformio.org/page/librarymanager/ldf.html | ||||||
							
								
								
									
										18
									
								
								platformio.ini
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								platformio.ini
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | ; PlatformIO Project Configuration File | ||||||
|  | ; | ||||||
|  | ;   Build options: build flags, source filter | ||||||
|  | ;   Upload options: custom upload port, speed and extra flags | ||||||
|  | ;   Library options: dependencies, extra library storages | ||||||
|  | ;   Advanced options: extra scripting | ||||||
|  | ; | ||||||
|  | ; Please visit documentation for the other options and examples | ||||||
|  | ; https://docs.platformio.org/page/projectconf.html | ||||||
|  |  | ||||||
|  | [env:uno] | ||||||
|  | platform = atmelavr | ||||||
|  | board = uno | ||||||
|  | framework = arduino | ||||||
|  | lib_deps =  | ||||||
|  | 	bblanchon/ArduinoJson@^6.17.2 | ||||||
|  | 	knolleary/PubSubClient@^2.8 | ||||||
|  | 	paulstoffregen/Ethernet@0.0.0-alpha+sha.9f41e8231b | ||||||
							
								
								
									
										318
									
								
								src/main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										318
									
								
								src/main.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,318 @@ | |||||||
|  | #include <Arduino.h> | ||||||
|  | #include <SPI.h> | ||||||
|  | #include <Ethernet.h> | ||||||
|  | #include <PubSubClient.h> | ||||||
|  | #include <ArduinoJson.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | // Update these with values suitable for your network. | ||||||
|  | byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xEA }; | ||||||
|  | IPAddress ip(192, 168, 89, 205); | ||||||
|  | IPAddress mqttServerIP(192, 168, 89, 95); | ||||||
|  | const char *mqttUser = "default"; | ||||||
|  | const char *mqttPassword = "12345678"; | ||||||
|  |  | ||||||
|  | const char *doorBellTopic = "doorBell"; | ||||||
|  | const char *postboxFlapTopic = "postboxFlap"; | ||||||
|  | const char *postboxDoorTopic = "postboxDoor"; | ||||||
|  | const char *doorBellTriggerSoundTopic = "doorBellTrigger"; | ||||||
|  | const char *postboxLightTopic = "postboxLight"; | ||||||
|  |  | ||||||
|  | EthernetClient ethClient; | ||||||
|  | EthernetServer server(80); | ||||||
|  | PubSubClient mqttClient(ethClient); | ||||||
|  | #define DOOR_BELL_BUTTON_PIN 7 | ||||||
|  | #define POSTBOX_FLAP_PIN 5 | ||||||
|  | #define POSTBOX_DOOR_PIN 3 | ||||||
|  | // Output pins | ||||||
|  | #define LED_PIN 13 | ||||||
|  | #define DOOR_BELL_BUZZER_PIN 6 | ||||||
|  | #define POSTBOX_LIGHT_PIN 4 | ||||||
|  |  | ||||||
|  | struct { | ||||||
|  |   const uint8_t pin; | ||||||
|  |   const unsigned long quietAfterTriggerFor_ms; | ||||||
|  |   unsigned long lastTrigger_ts; | ||||||
|  |   bool isTriggered; | ||||||
|  |   const char *topic; | ||||||
|  | } myInputs[] = { | ||||||
|  |   { DOOR_BELL_BUTTON_PIN, 500, 0 , false, doorBellTopic }, | ||||||
|  |   { POSTBOX_FLAP_PIN, 1000, 0, false, postboxFlapTopic }, | ||||||
|  |   { POSTBOX_DOOR_PIN, 1000, 0, false, postboxDoorTopic } | ||||||
|  | }; | ||||||
|  | #define NUM_INPUTS (sizeof(myInputs) / sizeof(myInputs[0])) | ||||||
|  | int ledState = LOW; | ||||||
|  |  | ||||||
|  | struct { | ||||||
|  |   const uint8_t pin; | ||||||
|  |   const unsigned long triggerTime_ms; | ||||||
|  |   bool isTriggered; | ||||||
|  |   unsigned long lastTrigger_ts; | ||||||
|  |   const char *listenTopic; // can be triggered by mqtt message as well | ||||||
|  | } myOutputs[] = { | ||||||
|  |   { DOOR_BELL_BUZZER_PIN, 500, false, 0, doorBellTriggerSoundTopic}, | ||||||
|  |   { POSTBOX_LIGHT_PIN, 30000, false, 0, postboxLightTopic} | ||||||
|  | }; | ||||||
|  | #define NUM_OUTPUTS (sizeof(myOutputs) / sizeof(myOutputs[0])) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void switchOutputOn(unsigned int outputNumber) { | ||||||
|  |   Serial.print(F("Switch output on: ")); | ||||||
|  |   Serial.print(outputNumber); | ||||||
|  |   Serial.print(F(" (pin ")); | ||||||
|  |   Serial.print(myOutputs[outputNumber].pin); | ||||||
|  |   Serial.print(F(") topic ")); | ||||||
|  |   Serial.println(myOutputs[outputNumber].listenTopic); | ||||||
|  |   digitalWrite(myOutputs[outputNumber].pin, LOW); | ||||||
|  |   myOutputs[outputNumber].isTriggered = true; | ||||||
|  |   myOutputs[outputNumber].lastTrigger_ts = millis(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void switchOutputOff(unsigned int outputNumber) { | ||||||
|  |   Serial.print(F("Switch output off: ")); | ||||||
|  |   Serial.print(outputNumber); | ||||||
|  |   Serial.print(F(" (pin ")); | ||||||
|  |   Serial.print(myOutputs[outputNumber].pin); | ||||||
|  |   Serial.print(F(") topic ")); | ||||||
|  |   Serial.println(myOutputs[outputNumber].listenTopic); | ||||||
|  |   digitalWrite(myOutputs[outputNumber].pin, HIGH); | ||||||
|  |   myOutputs[outputNumber].isTriggered = false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void checkOutputAutoOff() { | ||||||
|  |   static bool headerDone = false; | ||||||
|  |   for (unsigned int outputNumber=0; outputNumber<NUM_OUTPUTS; ++outputNumber) { | ||||||
|  |  | ||||||
|  |     if (myOutputs[outputNumber].isTriggered) { | ||||||
|  |       if (!headerDone) { | ||||||
|  |         Serial.print(F("checkOutputAutoOff: ts=")); Serial.println(millis()); | ||||||
|  |         headerDone = true; | ||||||
|  |       } | ||||||
|  |       //Serial.print(outputNumber); Serial.print(": "); | ||||||
|  |       //Serial.println(myOutputs[outputNumber].lastTrigger_ts + myOutputs[outputNumber].triggerTime_ms); | ||||||
|  |       if ((myOutputs[outputNumber].lastTrigger_ts + myOutputs[outputNumber].triggerTime_ms) < millis()) { | ||||||
|  |         Serial.println(F("Auto off output:")); | ||||||
|  |         switchOutputOff(outputNumber); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void mqttReceiveMessage(char* topic, uint8_t* payload, unsigned int length) { | ||||||
|  |   Serial.print(F("Message arrived [")); | ||||||
|  |   Serial.print(topic); | ||||||
|  |   Serial.print(F("] ")); | ||||||
|  |   Serial.print(length); | ||||||
|  |   Serial.print(F(" bytes: ")); | ||||||
|  |   Serial.println((char *) payload); | ||||||
|  |   for (unsigned int i=0;i<length;i++) { | ||||||
|  |     Serial.print((char)payload[i]); | ||||||
|  |   } | ||||||
|  |   Serial.println(); | ||||||
|  |   bool handlerFound = false; | ||||||
|  |   for (unsigned int i=0; i<NUM_OUTPUTS; ++i) { | ||||||
|  |     if (strcmp(myOutputs[i].listenTopic, topic) == 0) { | ||||||
|  |       handlerFound = true; | ||||||
|  |       if (strncmp((char *) payload, "on", length < 2 ? length : 2) == 0) { | ||||||
|  |         switchOutputOn(i); | ||||||
|  |       } else if (strncmp((char *) payload, "off", length < 3 ? length : 3) == 0) { | ||||||
|  |         switchOutputOff(i); | ||||||
|  |       } else { | ||||||
|  |         Serial.print(F("Unknown MQTT message payload received, topic: ")); | ||||||
|  |         Serial.print(topic); | ||||||
|  |         Serial.print(F(", payload: ")); | ||||||
|  |         Serial.println((char *) payload); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (!handlerFound) { | ||||||
|  |     Serial.print(F("Unknown MQTT message received, topic: ")); | ||||||
|  |     Serial.print(topic); | ||||||
|  |     Serial.print(F(", payload: ")); | ||||||
|  |     Serial.println((char *) payload); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void reconnect() { | ||||||
|  |   // Loop until we're reconnected | ||||||
|  |   while (!mqttClient.connected()) { | ||||||
|  |     Serial.print(F("Attempting MQTT connection...")); | ||||||
|  |     // Attempt to connect | ||||||
|  |     if (mqttClient.connect("doorBellGateway", mqttUser, mqttPassword)) { | ||||||
|  |       Serial.println(F("connected")); | ||||||
|  |       // Once connected, publish an announcement... | ||||||
|  |       // mqttClient.publish("hello","hello world"); | ||||||
|  |       // ... and resubscribe | ||||||
|  |       Serial.println(F("MQTT subscribe doorbell")); | ||||||
|  |       if (!mqttClient.subscribe("doorbell")) { | ||||||
|  |         Serial.println(F("ERROR: Failed to subscribe")); | ||||||
|  |       } | ||||||
|  |       for (unsigned int i=0; i<NUM_OUTPUTS; ++i) { | ||||||
|  |         Serial.print(F("MQTT subscribe ")); Serial.println(myOutputs[i].listenTopic); | ||||||
|  |         if (!mqttClient.subscribe(myOutputs[i].listenTopic)) { | ||||||
|  |           Serial.println(F("ERROR: Failed to subscribe")); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     } else { | ||||||
|  |       Serial.print(F("failed, rc=")); | ||||||
|  |       Serial.print(mqttClient.state()); | ||||||
|  |       Serial.println(F(" try again in 5 seconds")); | ||||||
|  |       // Wait 5 seconds before retrying | ||||||
|  |       delay(5000); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void sendMqttMessage(const char *topic, const char *message) { | ||||||
|  |   reconnect(); | ||||||
|  |   mqttClient.publish(topic, message); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void setup() | ||||||
|  | { | ||||||
|  |   // Initialize serial port | ||||||
|  |   Serial.begin(9600); | ||||||
|  |   while (!Serial) continue; | ||||||
|  |   Serial.println(F("Arduino Door Bell MQTT Gateway started.")); | ||||||
|  |  | ||||||
|  |   mqttClient.setServer(mqttServerIP, 1883); | ||||||
|  |   mqttClient.setCallback(mqttReceiveMessage); | ||||||
|  |  | ||||||
|  |   // Initialize Ethernet libary | ||||||
|  |   if (!Ethernet.begin(mac)) { | ||||||
|  |     Serial.println(F("Failed to initialize Ethernet library")); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Start to listen | ||||||
|  |   server.begin(); | ||||||
|  |   Serial.println(F("Server is ready.")); | ||||||
|  |   Serial.print(F("Please connect to http://")); | ||||||
|  |   Serial.println(Ethernet.localIP()); | ||||||
|  |  | ||||||
|  |   // setup the input and output pins | ||||||
|  |   for (unsigned int i = 0; i < NUM_INPUTS; i++) { | ||||||
|  |     pinMode(myInputs[i].pin, INPUT_PULLUP); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Setup the LED : | ||||||
|  |   for (unsigned int i=0; i < NUM_OUTPUTS; ++i) { | ||||||
|  |     pinMode(myOutputs[i].pin, OUTPUT); | ||||||
|  |     switchOutputOff(i); | ||||||
|  |   } | ||||||
|  |   pinMode(LED_PIN, OUTPUT); | ||||||
|  |   digitalWrite(LED_PIN, ledState); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void checkInputSignals() { | ||||||
|  |   bool needToToggleLed = false; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   for (unsigned int i = 0; i < NUM_INPUTS; i++)  { | ||||||
|  |     if (millis()-myInputs[i].lastTrigger_ts > myInputs[i].quietAfterTriggerFor_ms) { | ||||||
|  |       if (!digitalRead(myInputs[i].pin)) { | ||||||
|  |         // input is triggered, compare with existing state | ||||||
|  |         if (myInputs[i].isTriggered) { | ||||||
|  |           // was triggered as well, could send a retrigger now | ||||||
|  |           Serial.print(F("Re-Trigger pin ")); Serial.println(myInputs[i].pin); | ||||||
|  |           sendMqttMessage(myInputs[i].topic, "re-trigger"); | ||||||
|  |           needToToggleLed = true; | ||||||
|  |         } else { | ||||||
|  |           // handle trigger now | ||||||
|  |           myInputs[i].isTriggered = true; | ||||||
|  |           // send Trigger | ||||||
|  |           Serial.print(F("Trigger pin ")); Serial.println(myInputs[i].pin); | ||||||
|  |           sendMqttMessage(myInputs[i].topic, "trigger"); | ||||||
|  |           needToToggleLed = true; | ||||||
|  |         } | ||||||
|  |         myInputs[i].lastTrigger_ts = millis(); | ||||||
|  |       } else { | ||||||
|  |         // no trigger seen, if it was before, send a "released" message | ||||||
|  |         if (myInputs[i].isTriggered) { | ||||||
|  |           myInputs[i].isTriggered = false; | ||||||
|  |           myInputs[i].lastTrigger_ts = millis(); | ||||||
|  |           Serial.print(F("Released pin ")); Serial.println(myInputs[i].pin); | ||||||
|  |           sendMqttMessage(myInputs[i].topic, "release"); | ||||||
|  |           needToToggleLed = true; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // if a LED toggle has been flagged : | ||||||
|  |   if ( needToToggleLed ) { | ||||||
|  |     // Toggle LED state : | ||||||
|  |     ledState = !ledState; | ||||||
|  |     digitalWrite(LED_PIN, ledState); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void checkWebRequest() { | ||||||
|  |   // Wait for an incomming connection | ||||||
|  |   EthernetClient client = server.available(); | ||||||
|  |  | ||||||
|  |   // Do we have a client? | ||||||
|  |   if (!client) return; | ||||||
|  |  | ||||||
|  |   Serial.println(F("New client on web ingress")); | ||||||
|  |  | ||||||
|  |   // Read the request (we ignore the content in this example) | ||||||
|  |   while (client.available()) client.read(); | ||||||
|  |  | ||||||
|  |   // Allocate a temporary JsonDocument | ||||||
|  |   // Use arduinojson.org/v6/assistant to compute the capacity. | ||||||
|  |   StaticJsonDocument<500> doc; | ||||||
|  |    | ||||||
|  |   for (unsigned int pin = 0; pin < NUM_INPUTS; pin++) { | ||||||
|  |     doc[myInputs[pin].topic] = myInputs[pin].isTriggered ? "triggered" : "released"; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Create the "digital" array | ||||||
|  |   JsonArray digitalValues = doc.createNestedArray("digitalPin"); | ||||||
|  |   for (unsigned int pin = 0; pin < 14; pin++) { | ||||||
|  |     // Read the digital input | ||||||
|  |     int value = digitalRead(pin); | ||||||
|  |  | ||||||
|  |     // Add the value at the end of the array | ||||||
|  |     digitalValues.add(value); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Serial.print(F("Sending: ")); | ||||||
|  |   serializeJson(doc, Serial); | ||||||
|  |   Serial.println(); | ||||||
|  |  | ||||||
|  |   // Write response headers | ||||||
|  |   client.println(F("HTTP/1.0 200 OK")); | ||||||
|  |   client.println(F("Content-Type: application/json")); | ||||||
|  |   client.println(F("Connection: close")); | ||||||
|  |   client.print(F("Content-Length: ")); | ||||||
|  |   // client.println(measureJsonPretty(doc)); | ||||||
|  |   client.println(measureJson(doc)); | ||||||
|  |   client.println(); | ||||||
|  |  | ||||||
|  |   // Write JSON document | ||||||
|  |   //serializeJsonPretty(doc, client); | ||||||
|  |   serializeJson(doc, client); | ||||||
|  |    | ||||||
|  |   // Disconnect | ||||||
|  |   client.stop(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void loop() { | ||||||
|  |   // Client | ||||||
|  |   if (!mqttClient.connected()) { | ||||||
|  |     reconnect(); | ||||||
|  |   } | ||||||
|  |   mqttClient.loop(); | ||||||
|  |  | ||||||
|  |   checkInputSignals(); | ||||||
|  |  | ||||||
|  |   checkWebRequest(); | ||||||
|  |  | ||||||
|  |   checkOutputAutoOff(); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										11
									
								
								test/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								test/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  |  | ||||||
|  | This directory is intended for PlatformIO Unit Testing and project tests. | ||||||
|  |  | ||||||
|  | Unit Testing is a software testing method by which individual units of | ||||||
|  | source code, sets of one or more MCU program modules together with associated | ||||||
|  | control data, usage procedures, and operating procedures, are tested to | ||||||
|  | determine whether they are fit for use. Unit testing finds problems early | ||||||
|  | in the development cycle. | ||||||
|  |  | ||||||
|  | More information about PlatformIO Unit Testing: | ||||||
|  | - https://docs.platformio.org/page/plus/unit-testing.html | ||||||
		Reference in New Issue
	
	Block a user