Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Analog Input Update #3

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

*.svd
*.cfg
*.json
296 changes: 242 additions & 54 deletions reef-pi.ino
Original file line number Diff line number Diff line change
@@ -1,58 +1,80 @@
#include <WiFi.h>
#include "Wire.h"
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <TokenIterator.h>
#include <UrlTokenBindings.h>
#include <OneWire.h>
#include <DallasTemperature.h>

//////////////
// SETTINGS //
//////////////
#define OUTLET_COUNT 6
#define INLET_COUNT 4
#define JACK_COUNT 4
#define DS18B20_COUNT 2
#define PH_COUNT 1
#define FLOW_METER_COUNT 1
#define ANALOG_INPUT_COUNT 2
#define PWM_FREQ 5000
#define PWM_RESOLUTION 8



const char *ssid = "SET_SSID";
const char *password = "SET_PASSWORD";

const int outletPins[OUTLET_COUNT] = { 5, 16, 17, 18, 19, 23 };
const int inletPins[INLET_COUNT] = { 1, 3, 14, 36 };
const int jackPins[JACK_COUNT] = { 12, 13, 14, 27 };
const int pwmChannels[JACK_COUNT] = { 0, 1, 2, 3 };
const int analogInputPins[ANALOG_INPUT_COUNT] = { 32, 33 };
const int oneWirePin = 4;
const uint8_t OUTLET_PINS[OUTLET_COUNT] = { 5, 16, 17, 18, 19, 23 };
const uint8_t INLET_PINS[INLET_COUNT] = { 25, 26, 36, 39 };
const uint8_t JACK_PINS[JACK_COUNT] = { 12, 13, 14, 27 };
const uint8_t PWM_CHANNELS[JACK_COUNT] = { 0, 1, 2, 3 };
const uint8_t PH_ADDR[PH_COUNT] = {98};
const uint8_t FLOW_METER_PINS[1] = {34};
const uint8_t ANALOG_INPUT_PINS[ANALOG_INPUT_COUNT] = { 32, 33 };
const uint8_t ONE_WIRE_PINS[1] = {4};

//////////
// INIT //
//////////
volatile unsigned int flowCounts;
unsigned int lastFlowCounts;

OneWire oneWire(oneWirePin);
OneWire oneWire(ONE_WIRE_PINS[0]);
DallasTemperature ds18b20(&oneWire);
AsyncWebServer server(80);


void setup() {
Serial.begin(115200);
for (int i = 0; i < OUTLET_COUNT; i++) {
pinMode(outletPins[i], OUTPUT);
}
//while(!Serial);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);

for (int i = 0; i < INLET_COUNT; i++) {
pinMode(inletPins[i], INPUT);
startPins(0,OUTLET_PINS,OUTLET_COUNT);
startPins(1,INLET_PINS,INLET_COUNT);
startPins(2,JACK_PINS,JACK_COUNT);
if (DS18B20_COUNT){
startPins(3,ONE_WIRE_PINS,DS18B20_COUNT);
}
for (int i = 0; i < JACK_COUNT; i++) {
ledcSetup(pwmChannels[i], PWM_FREQ, PWM_RESOLUTION);
ledcAttachPin(jackPins[i], pwmChannels[i]);
if (PH_COUNT){
startPins(4,PH_ADDR,PH_COUNT);
}
for (int i = 0; i < ANALOG_INPUT_COUNT; i++) {
pinMode(analogInputPins[i], INPUT);
if (FLOW_METER_COUNT){
startPins(5,FLOW_METER_PINS,FLOW_METER_COUNT);
}
if (ANALOG_INPUT_COUNT){
startPins(6,ANALOG_INPUT_PINS,ANALOG_INPUT_COUNT);
}
ds18b20.begin();

WiFi.begin(ssid, password);
Serial.println("Starting WiFi..");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
digitalWrite(LED_BUILTIN, HIGH);
delay(50);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
Serial.println("Connecting to WiFi..");
Serial.println("\tConnecting to WiFi..");
}
Serial.print("\tWiFi-IP:");
Serial.println(WiFi.localIP());
server.on("/outlets/*", HTTP_POST, switchOutlet);
server.on("/inlets/*", HTTP_GET, readInlet);
Expand All @@ -62,9 +84,101 @@ void setup() {
server.begin();
}

///////////////
// MAIN LOOP //
///////////////
void loop() {
if (WiFi.status() == WL_CONNECTED){
digitalWrite(LED_BUILTIN, HIGH);
delay(950);
digitalWrite(LED_BUILTIN, LOW);
delay(50);
}
else{
digitalWrite(LED_BUILTIN, HIGH);
delay(50);
digitalWrite(LED_BUILTIN, LOW);
delay(950);
}
lastFlowCounts = flowCounts;
flowCounts = 0;
}

///////////////
// FUNCTIONS //
///////////////
// start pins to their respective functions defined in settings
void startPins(uint8_t type, const uint8_t PINS[], uint8_t count){
const char PIN_NAMES[][14] = {" Outlets",
" Inlets",
" Jacks",
" DS18B20",
" I2C",
" Flowmeters",
"Analog Inputs"};
size_t subIDs[] = { 0,
DS18B20_COUNT,
PH_COUNT,
FLOW_METER_COUNT,
ANALOG_INPUT_COUNT};
for (size_t i=1; i<5; i++){
subIDs[i] += subIDs[i-1];
}
Serial.print("Starting ");
Serial.print(PIN_NAMES[type]);
Serial.println("..");

for (size_t i = 0; i < count; i++) {
Serial.print("\tPin");
Serial.println(PINS[i]);

//Init OUTPUT
if (type == 0){
pinMode(PINS[i], OUTPUT);
}
//Init INPUT
if (type == 1){
pinMode(PINS[i], INPUT);
}
//Init JACKS
if (type == 2){
ledcSetup(PWM_CHANNELS[i], PWM_FREQ, PWM_RESOLUTION);
ledcAttachPin(PINS[i], PWM_CHANNELS[i]);
}
//Init DS18B20
if (type == 3){
ds18b20.begin();
}
// start I2C
if (type == 4){
Wire.begin();
Serial.print("\tbus-clock:");
Serial.println(Wire.getClock());
Serial.print("\tbus-timeout:");
Serial.println(Wire.getTimeOut());
}
//Init FLOWMETER
if (type == 5){
pinMode(PINS[i], INPUT);
flowCounts = 0;
lastFlowCounts = 0;
attachInterrupt(PINS[i], flowMeterCounter, FALLING);
}
//Init ANALOGINPUT
if (type == 6){
pinMode(PINS[i], INPUT);
}
//Message for Pin IDs
if (type > 2){
Serial.print("\tPin IDs:");
Serial.print(subIDs[type-3]);
Serial.print("-");
Serial.println(subIDs[type-2]-1);
}
}
}

// extract parameters from URL (?)
UrlTokenBindings parseURL(AsyncWebServerRequest *request, char templatePath[]) {
char urlBuffer[30];
request->url().toCharArray(urlBuffer, 30);
Expand All @@ -78,18 +192,24 @@ UrlTokenBindings parseURL(AsyncWebServerRequest *request, char templatePath[]) {
void switchOutlet(AsyncWebServerRequest *request) {
char path[] = "/outlets/:id/:action";
UrlTokenBindings bindings = parseURL(request, path);

int id = String(bindings.get("id")).toInt();
const char* binding_id = bindings.get("id");
if (binding_id == NULL){
Serial.println("NULL pointer error");
request->send(409, "text/plain", "NULL pointer error");
return;
}
int id = String(binding_id).toInt();

if (id < 0 || id >= OUTLET_COUNT) {
request->send(409, "text/plain", "invalid outlet pin id");
}
String action = String(bindings.get("action"));
Serial.println("Outlet Pin:" + String(outletPins[id]) + ", Action:" + action);
Serial.println("Outlet Pin:" + String(OUTLET_PINS[id]) + ", Action:" + action);
if (action.equals("on")) {
digitalWrite(outletPins[id], HIGH);
digitalWrite(OUTLET_PINS[id], HIGH);
request->send(200, "text/plain", "high");
} else if (action.equals("off")) {
digitalWrite(outletPins[id], LOW);
digitalWrite(OUTLET_PINS[id], LOW);
request->send(200, "text/plain", "low");
} else {
request->send(409, "text/plain", "unrecognized action");
Expand All @@ -99,52 +219,120 @@ void switchOutlet(AsyncWebServerRequest *request) {
void readInlet(AsyncWebServerRequest *request) {
char path[] = "/inlets/:id";
UrlTokenBindings bindings = parseURL(request, path);
int id = String(bindings.get("id")).toInt();
const char* binding_id = bindings.get("id");
if (binding_id == NULL){
Serial.println("NULL pointer error");
request->send(409, "text/plain", "NULL pointer error");
return;
}
int id = String(binding_id).toInt();
if (id < 0 || id >= INLET_COUNT) {
request->send(409, "text/plain", "invalid inlet pin id");
}
int v = digitalRead(inletPins[id]);
Serial.println("Inlet pin:" + String(inletPins[id]) + " Value:" + String(v));

int v = digitalRead(INLET_PINS[id]);
Serial.println("Inlet pin:" + String(INLET_PINS[id]) + " Value:" + String(v));
request->send(200, "text/plain", String(v));
}

void setJackValue(AsyncWebServerRequest *request) {
char path[] = "/jacks/:id/:value";
UrlTokenBindings bindings = parseURL(request, path);

const char* binding_id = bindings.get("id");
if (binding_id == NULL){
Serial.println("NULL pointer error");
request->send(409, "text/plain", "NULL pointer error");
return;
}
int id = String(binding_id).toInt();

const char* binding_dc = bindings.get("value");
if (binding_dc == NULL){
Serial.println("NULL pointer error");
request->send(409, "text/plain", "NULL pointer error");
return;
}
int dc = String(binding_dc).toInt();

if (id < 0 || id >= JACK_COUNT) {
request->send(409, "text/plain", "invalid inlet pin id");
return;
}
if (dc > 255) {
dc = 255;
}
if (dc < 0) {
dc = 0;
}
Serial.println("PWM Pin" + String(JACK_PINS[id]) + " DutyCycle:" + String(dc));
ledcWrite(PWM_CHANNELS[id], dc);
request->send(200, "text/plain", String(dc));
}

void readAnalogInput(AsyncWebServerRequest *request) {
char path[] = "/analog_inputs/:id";
UrlTokenBindings bindings = parseURL(request, path);
int id = String(bindings.get("id")).toInt();
const char* binding_id = bindings.get("id");
if (binding_id == NULL){
Serial.println("NULL pointer error");
request->send(409, "text/plain", "NULL pointer error");
return;
}
int id = String(binding_id).toInt();

if (id < 0 || id > ANALOG_INPUT_COUNT) {
if (id < 0 || id > DS18B20_COUNT + PH_COUNT + FLOW_METER_COUNT + ANALOG_INPUT_COUNT - 1) {
request->send(409, "text/plain", "invalid inlet pin id");
return;
}
float value;
if (id == 0) {
int pin, subId;
if (id < DS18B20_COUNT) {
ds18b20.requestTemperatures();
value = ds18b20.getTempCByIndex(0);
pin = ONE_WIRE_PINS[0];
value = ds18b20.getTempCByIndex(id);
} else if (id < DS18B20_COUNT + PH_COUNT) {
subId = id - DS18B20_COUNT;
pin = PH_ADDR[subId];
value = readPh(subId);
} else if (id < DS18B20_COUNT + PH_COUNT + FLOW_METER_COUNT) {
subId = id - DS18B20_COUNT - PH_COUNT;
pin = FLOW_METER_PINS[subId];
value = readFlowMeter();
} else {
value = analogRead(analogInputPins[id]);
subId = id - DS18B20_COUNT - PH_COUNT - FLOW_METER_COUNT;
pin = ANALOG_INPUT_PINS[subId];
value = analogRead(ANALOG_INPUT_PINS[subId]);
}
Serial.println("Analog Input pin:" + String(analogInputPins[id]) + " Value:" + String(value));
request->send(200, "text/plain", String(value));
Serial.println("Analog Input pin:" + String(pin) + " Value:" + String(value));
//value == -1.0, avoiding rounding problems
if (value < -0.5) request->send(409, "text/plain", "I2C communication error");
else request->send(200, "text/plain", String(value));
}

float readPh(uint8_t subId){
uint8_t bytes = 10;
Wire.beginTransmission(PH_ADDR[subId]);
Wire.write(byte(0x52));
Wire.write(byte(0x00));
uint8_t error = Wire.endTransmission(false);

uint8_t bytesReceived = Wire.requestFrom(PH_ADDR[subId], bytes);
if((bool)bytesReceived){
Wire.read(); //skip first byte
uint8_t temp[--bytesReceived]; //read the rest of the bytes
Wire.readBytes(temp, bytesReceived);
//log_print_buf(temp, bytesReceived);
return String((char*)temp).toFloat();
}
return -1.0;
}

float readFlowMeter(){
return float(lastFlowCounts);
}

void setJackValue(AsyncWebServerRequest *request) {
char path[] = "/jacks/:id/:value";
UrlTokenBindings bindings = parseURL(request, path);
int id = String(bindings.get("id")).toInt();
int dc = String(bindings.get("value")).toInt();
if (id < 0 || id >= JACK_COUNT) {
request->send(409, "text/plain", "invalid inlet pin id");
}
if (dc > 255) {
dc = 255;
}
if (dc < 0) {
dc = 0;
}
Serial.println("PWM Pin" + String(jackPins[id]) + " DutyCycle:" + String(dc));
ledcWrite(pwmChannels[id], dc);
request->send(200, "text/plain", String(dc));
// counter function to increment flowmeter value
void ARDUINO_ISR_ATTR flowMeterCounter(){
flowCounts++;
}