I wrote an Arduino sketch for the nodeMCU that can be used to enable unsupported interfaces/devices in BruControl. Hopefully other people out there can make some use of it as well.
Currently BruControl does not offer generic support for digital communication standards like UART, I2C, SPI, or 1-wire. For the latter 3 BruControl does support these interfaces, but only for a single device per bus standard (I2C = LCD display, SPI = RTC amplifier, 1-wire = temp sensor). Enabling generic support for any device that uses one of these 4 communication interfaces will not be a trivial task. For example, some UART devices will send out status information at a fixed time interval, whereas other devices require you to send a command to read a value. I2C gets more complicated, as most devices will allow you to read from the device with a single read command. Other devices require you to write an address value to a "read address" register before reading the value from a different register. On top of that there are multiple different ways to read back more than 8 bits from an I2C device.
The framework will communicate to BruControl over WiFi through BruControl's HTTP data exchange interface to read and write global values in BruControl. The user can add their own code in the framework to act upon global values and send back status to BruControl. This does require the user to be able to write their own Arduino sketch to interface with whatever device they are enabling support for. In fact, I would start by writing a sketch to interface with the unsupported device using the serial interface on the nodeMCU before integrating your code into this framework. I tried to add as many comments to make it self explanatory as to what and where you need to add your own code.
Disclaimer: There are probably better/more efficient ways to write this code and limited testing has been done on this framework.
This was written on version 1.8.10 of the Arduino IDE. Note, the nodeMCU is not supported in the Arduino IDE by default. You can find instructions for that here.
https://www.instructables.com/id/Quick-Start-to-Nodemcu-ESP8266-on-Arduino-IDE/
Currently BruControl does not offer generic support for digital communication standards like UART, I2C, SPI, or 1-wire. For the latter 3 BruControl does support these interfaces, but only for a single device per bus standard (I2C = LCD display, SPI = RTC amplifier, 1-wire = temp sensor). Enabling generic support for any device that uses one of these 4 communication interfaces will not be a trivial task. For example, some UART devices will send out status information at a fixed time interval, whereas other devices require you to send a command to read a value. I2C gets more complicated, as most devices will allow you to read from the device with a single read command. Other devices require you to write an address value to a "read address" register before reading the value from a different register. On top of that there are multiple different ways to read back more than 8 bits from an I2C device.
The framework will communicate to BruControl over WiFi through BruControl's HTTP data exchange interface to read and write global values in BruControl. The user can add their own code in the framework to act upon global values and send back status to BruControl. This does require the user to be able to write their own Arduino sketch to interface with whatever device they are enabling support for. In fact, I would start by writing a sketch to interface with the unsupported device using the serial interface on the nodeMCU before integrating your code into this framework. I tried to add as many comments to make it self explanatory as to what and where you need to add your own code.
Disclaimer: There are probably better/more efficient ways to write this code and limited testing has been done on this framework.
This was written on version 1.8.10 of the Arduino IDE. Note, the nodeMCU is not supported in the Arduino IDE by default. You can find instructions for that here.
https://www.instructables.com/id/Quick-Start-to-Nodemcu-ESP8266-on-Arduino-IDE/
Code:
/**********************************************************************************
* BruControl nodeMCU http bridge
* Version: 0.2
*
* This framework provides a bridge between a nodeMCU and BruControl using BruControl's
* http GET/PUT data exchange protocol.
* Basic flow
* 1. Every checkInterval each BruControl global variable in the globalsToRead array is read
* and its value is placed in the corresonding index in the globalReadValues array.
* 2. Every calcInterval user defined code is ran to:
* process inputs
* interface with devices
* calculate return values
* 3. Every sendInterval each BruControl global variable in the globalsToWrite array's
* corresponding value in the globalValuesToWrite array is sent back to BruControl.
*
* General use of this framework.
* Place your user code within the @@@@@@@@@@@ sections
* There should be no need to modify the code outside of these sections.
*
************************************************************************************/
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
* Place User comments aboout your application here.
*
*
*
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
/**********************************************************************************
* BruControl Settings
*
* Modify the following code for the number of globals you want to read and update
* from/to BruControl, with they names of each global as it is named in BruControl.
*
* Set the server IP address and port as needed.
*
***********************************************************************************/
// The following are used to define what global variables in BruControl to monitor and update.
#define READSIZE 3 // Number of global variables to read
#define WRITESIZE 2 // Number of global variables to update
// Optional to define indices for variables to make it easier to use them
// Read Array Indices
#define GR1INDEX 0
#define GR2INDEX 1
#define GR3INDEX 2
// Write Array Indices
#define GW1INDEX 0
#define GW2INDEX 1
// Create arrays
String globalsToRead[READSIZE] = { "readGlobal1", "readGlobal2", "readGlobal3" }; // List of global variables to read as they are named in BruControl
String globalReadValues[READSIZE]; // Array to store read values in
String globalsToWrite[WRITESIZE] = { "writeGlobal1", "writeGlobal2" }; // List of global variables to update as they are named in BruControl
String globalValuesToWrite[WRITESIZE]; // Array to store write values in
// BruControl Server settings
char serverAddress[] = "192.192.192.192"; // BruControl Server IP Address
int port = 8000; // BruControl Server port
// Scheduling interval
unsigned long int delayInterval = 1000; // milliseconds between each time the main loop runs
/**********************************************************************************
* End BruControl Settings
***********************************************************************************/
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
* Place user defined initialization code below
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
// Put your definitions here
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
* End User defined/modifiable variables
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
String readString; //String loaded with results from HTTP get requests
char temp_string[300]; // temp string used for sprintf's and other crap
ESP8266WiFiMulti WiFiMulti;
void setup() {
Serial.begin(115200);
Serial.println();
WiFi.mode(WIFI_STA);
WiFiMulti.addAP("SSID", "PASSWORD"); //Change this to your Wifi settings
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(WiFi.localIP().toString());
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
* Place user defined setup code below
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
// Place your setup code here
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
* End user defined setup code
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
delay(5000);
}
/**********************************************************************************
* Main Loop to get inputs from BruControl, process them, calculate outputs,
* and send updates back to BruControl
*
* This allows you to use global variables in BruControl to interface with
* unsupported devices.
*
* In this case we are doing the following:
* Polling BruControl for HopsBossLocation updates
* HopsBossLocation is an integer from 0-7, 0 being home or closed, 1-7 corresponding
* to motor shell locations.
* Monitoring Serial port output of Hops-Boss for changes in:
* Current Posittion
* Currently Moving
* Send command to Hops-Boss to move to new position if:
* HopsBossLocation does not equal current location
* and we are not currently moving
* Upon stopping moving check to make sure:
* Current Position is the same as HopsBossLocation
* Send HopsBossmoving status back to BruControl
*
***********************************************************************************/
void loop() {
Serial.println("### Starting Main Loop ###################################################");
Serial.println(" ## Starting to read variables from BruControl #####");
getGlobals(); // get updates from BruControl
Serial.println(" ## Done reading variables from BruControl #####");
Serial.println(" @@ Starting to Parse and Caculate user code @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@U@@@@@@@@@@@@");
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
* Place user function calls here
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
// process inputs, interface with devices, and calculate return values every calcInterval
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
* End user function calls
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
Serial.println(" @@ Done with user code @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
Serial.println(" ## Starting to write outputs back to BruControl #####");
sendGlobals(); // send updates to BruControl
Serial.println(" ## Done writing outputs to BruControl #####");
delay(delayInterval); // set delayInterval to how long you want to wait between executing the main loop
}
/**********************************************************************************
* End Main Loop
***********************************************************************************/
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
* Place user defined functions below for processing inputs, interfacing with
* devices, and calculating return values.
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
// Place your user functions here
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
* End user defined functions
*
* Start of framework functions
* Don't modify the code below here!!!!
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/**********************************************************************************
* getGlobals()
*
* Framework function to iterate through the array of BruControl global variables
* to get current values.
*
* This function will read all global variables in the globalsToRead array
* and fill the globalReadValues arrays with their current values.
*
* Do not modify this function. Instead set the following at the top of this file:
* READSIZE - number of global variables to update
* globalsToRead - names of global variables as they are named in BruControl
* globalReadValues - Values for each global variable
*
***********************************************************************************/
void getGlobals() {
int i;
for(i=0; i<READSIZE; i++) {
globalReadValues = getVariableValue(globalsToRead);
Serial.print(" readString Is: ");
Serial.print(globalsToRead);
Serial.print(", ");
Serial.println(globalReadValues);
}
}
/**********************************************************************************
* sendGlobals()
*
* Framework function to iterate through the array of BruControl global variables
* to send updates to.
*
* This function will send all global variables in the globalsToWrite array with
* corresponding values from the globalValuesToWrite array.
*
* Do not modify this function. Instead set the following at the top of this file:
* WRITESIZE - number of global variables to update
* globalsToWrite - names of global variables as they are named in BruControl
* globalValuestoWrite - Values for each global variable
*
***********************************************************************************/
void sendGlobals() {
int i;
for(i=0; i<WRITESIZE; i++) {
sendVariableValue(globalsToWrite, globalValuesToWrite);
Serial.print(" Write: ");
Serial.print(globalsToWrite);
Serial.print(", ");
Serial.println(globalValuesToWrite);
}
}
/**********************************************************************************
* getVariableValue()
* globalVariable - name of global variable as it appear in BruControl.
*
* Framework function to get values of individual BruControl global variables.
* This function is called by the getGlobals() framework function.
* The user should not call this function directly
*
* returns value of global variable in String form
*
***********************************************************************************/
String getVariableValue(String globalVariable) {
String payload = "";
StaticJsonDocument<512> jsonDoc;
char temp1[100];
char temp2[100];
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
WiFiClient client;
HTTPClient http;
globalVariable.toCharArray(temp1,100);
sprintf(temp2, "/global/%s", temp1);
if (http.begin(client, serverAddress, port, temp2)) {
// start connection and send HTTP header
int httpCode = http.GET();
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
payload = http.getString();
}
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
} else {
Serial.printf("[HTTP} Unable to connect\n");
}
}
payload.toCharArray(temp1,300);
DeserializationError error = deserializeJson(jsonDoc, temp1);
if(error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.c_str());
return "";
}
const char* returnValue = jsonDoc["Value"];
return returnValue;
}
/**********************************************************************************
* sendVariableValue()
* globalVariable - name of global variable as it appear in BruControl.
* variableValue - value of variable in string form to send back to BruControl.
*
* Framework function to send updates to individual BruControl global variables.
* This function is called by the sendGlobals() framework function.
* The user should not call this function directly
*
***********************************************************************************/
void sendVariableValue(String globalVariable, String variableValue) {
char temp1[100];
char temp2[100];
char temp3[100];
if ((WiFiMulti.run() == WL_CONNECTED)) {
WiFiClient client;
HTTPClient http;
globalVariable.toCharArray(temp1,100);
variableValue.toCharArray(temp2,100);
sprintf(temp3, "[{\"Name\":\"%s\",\"Value\":\"%s\"}]", temp1, temp2);
String jsonToWrite = temp3;
if (http.begin(client, serverAddress, port, "/globals")) { // HTTP
http.addHeader("Content-Type", "application/json");
http.addHeader("Content-Length", String(jsonToWrite.length()));
// start connection and send HTTP header
int httpCode = http.PUT(jsonToWrite);
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = http.getString();
}
} else {
Serial.printf("[HTTP] PUT... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
} else {
Serial.printf("[HTTP} Unable to connect\n");
}
}
}
Last edited: