Compare commits

...

10 Commits

Author SHA1 Message Date
Andrew 094ba87cc4
Merge pull request #2 from UAH-SD-Transformer-Monitor/UseTasks
3 months ago
Andrew Woodlee 8c9de7e2bf remove harmonics from data
3 months ago
Andrew Woodlee ab0b6a6424 v0.2
3 months ago
Andrew Woodlee 16c5f212a0 v0.1
3 months ago
Andrew Woodlee c34c62da31 fixes
3 months ago
Andrew Woodlee c8abafe9c3 fix temp sensor calls in ISR
3 months ago
Andrew Woodlee b8d05740aa more work on data queues
3 months ago
Andrew Woodlee 6009fa1f72 more work on queues
3 months ago
Andrew Woodlee 2807f22e59 more work on tasks and ISR
4 months ago
Andrew Woodlee 8af63a4790 dirty commit of start on tasks
4 months ago

@ -13,7 +13,8 @@
"initializer_list": "cpp",
"type_traits": "cpp",
"new": "cpp",
"ctime": "cpp"
"ctime": "cpp",
"*.tcc": "cpp"
},
"julia.environmentPath": "/home/andrew/Projects/SeniorDesign/esp32-tm-code"
}

@ -5,7 +5,7 @@ wifi:
# Your WiFi SSID
ssid: "Your-WiFi-SSID"
# Your WiFi Password
passwd: Your-Secret-WiFi-Password
password: "Your-Secret-WiFi-Password"
mqtt:
# Your MQTT server
server: your.mqtt-broker.tld

@ -39,10 +39,10 @@ if wifiConfig.get("ssid") == None:
print(f"wifi object variable SSID not defined. Define it in the config.yml file at the root of the project.")
os._exit(1)
if wifiConfig["password"] == None:
if wifiConfig.get("password") == None:
print(f"wifi object variable password not defined. Define it in the config.yml file at the root of the project.")
os._exit(1)
if mqttConfig["server"] == None:
if mqttConfig.get("server") == None:
print(f"mqtt object variable server not defined. Define it in the config.yml file at the root of the project.")
os._exit(1)

@ -3,6 +3,11 @@
#include <ArduinoJson.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <FreeRTOSConfig.h>
#include <freertos/task.h>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include <idf_additions.h>
@ -79,27 +84,84 @@ ATM90E36_IC SetupEic(ctLine, ic);
// we are using the ESP32's MAC address to provide a unique ID
String client_id = "xformermon-";
// GPIO where the DS18B20 is connected to
const int oilTempBus = 4;
const int cabinetTempBus = 9;
struct tempSensors {
DallasTemperature oil, cabinet;
};
DeviceAddress oilTempSensorAddr;
DeviceAddress cabinetTempSensorAddr;
// Setup a oneWire instance to communicate with any OneWire devices
OneWire cabinetTempBusOneWire(cabinetTempBus);
OneWire oilTempBusOneWire(oilTempBus);
OneWire cabinetTempBusOneWire(cabinetTempBus);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature cabinetTemp(&cabinetTempBusOneWire);
DallasTemperature oilTemp(&oilTempBusOneWire);
DallasTemperature oilTempSensor(&oilTempBusOneWire);
DallasTemperature cabinetTempSensor(&cabinetTempBusOneWire);
tempSensors monitorTempSensors{oilTempSensor, cabinetTempSensor};
StaticJsonDocument<256> dataStore[60];
time_t now;
// Data structs for queue
struct tempData {
float cabinet, oil;
};
struct tempSensors { // Structure declaration
DallasTemperature cabinet; // Cabinet Temp (DallasTemperature variable)
DallasTemperature oil; // Oil Temp (DallasTemperature variable)
struct powerData {
double active, apparent, reactive, factor;
};
tempSensors monitorTempSensors{cabinetTemp, oilTemp};
struct harmonicData {
double voltage, current;
};
struct energyData {
double import, exp;
};
// StaticJsonDocument<256> dataStore[60];
struct xformerMonitorData {
unsigned short sysStatus, meterStatus;
double lineCurrent, neutralCurrent, lineVoltage, phase;
tm *timeInfo;
tempData temps;
powerData power;
energyData energy;
};
// End data structs for queue
// Global to be used in ISR
xformerMonitorData sensorData;
// Variables for tasks
TaskHandle_t taskReadEIC;
TaskHandle_t taskSendData;
QueueHandle_t eicDataQueue;
// End variables for tasks
// Functions for tasks
void readEICData( void * pvParameters );
void sendSensorDataOverMQTT( void * pvParameters );
// End functions for tasks
// Timer variable and function
hw_timer_t *readEICTimer = NULL;
void IRAM_ATTR ReadData();
// End timer variable and function
struct xformerMonConfigData {
char *wifiSsid;
char *wifiPass;
char *mqttName;
char *mqttServerHost;
char *mqttUserName;
char *mqttPassword;
uint16_t mqttServerPort;
} monitorConfig;

@ -21,27 +21,21 @@ void ATM90E36_IC::begin(){
}
double ATM90E36_IC::GetLineVoltage()
{
double lv;
switch (ctLine)
{
case 'A':
return eic->GetLineVoltageA();
lv = eic->GetLineVoltageA();
case 'B':
return eic->GetLineVoltageB();
lv = eic->GetLineVoltageB();
case 'C':
return eic->GetLineVoltageC();
lv = eic->GetLineVoltageC();
break;
}
}
double ATM90E36_IC::GetSysStatus()
{
return eic->GetSysStatus0();
}
double ATM90E36_IC::GetActivePower()
{
this->meterStatus = eic->GetActivePowerA();
return meterStatus;
return lv;
}
double ATM90E36_IC::GetActivePower()
@ -56,8 +50,142 @@ void ATM90E36_IC::begin(){
ap = eic->GetActivePowerB();
break;
case 'C':
ap = this->eic->GetActivePowerC();
ap = eic->GetActivePowerC();
break;
}
return ap;
}
double ATM90E36_IC::GetVHarm()
{
double vh;
switch (ctLine)
{
case 'A':
vh = eic->GetVHarmA();
break;
case 'B':
vh = eic->GetVHarmB();
break;
case 'C':
vh = eic->GetVHarmC();
break;
}
return vh;
}
double ATM90E36_IC::GetCHarm()
{
double ch;
switch (ctLine)
{
case 'A':
ch = eic->GetVHarmA();
break;
case 'B':
ch = eic->GetVHarmB();
break;
case 'C':
ch = eic->GetVHarmC();
break;
}
return ch;
}
double ATM90E36_IC::GetPowerFactor()
{
double pf;
switch (ctLine)
{
case 'A':
pf = eic->GetPowerFactorA();
break;
case 'B':
pf = eic->GetPowerFactorB();
break;
case 'C':
pf = eic->GetPowerFactorC();
break;
}
return pf;
}
double ATM90E36_IC::GetApparentPower()
{
return eic->GetTotalApparentPower();
}
double ATM90E36_IC::GetPhase()
{
double p;
switch (ctLine)
{
case 'A':
p = eic->GetPhaseA();
break;
case 'B':
p = eic->GetPhaseB();
break;
case 'C':
p = eic->GetPhaseC();
break;
}
return p;
}
double ATM90E36_IC::GetLineCurrent()
{
double i;
switch (ctLine)
{
case 'A':
i = eic->GetLineCurrentA();
break;
case 'B':
i = eic->GetLineCurrentB();
break;
case 'C':
i = eic->GetLineCurrentC();
break;
}
return i;
}
double ATM90E36_IC::GetLineCurrentN()
{
return eic->GetLineCurrentN();
}
double ATM90E36_IC::GetTemperature()
{
return eic->GetTemperature();
}
double ATM90E36_IC::GetMeterStatus0()
{
return eic->GetMeterStatus0();
}
double ATM90E36_IC::GetMeterStatus1()
{
return eic->GetMeterStatus1();
}
double ATM90E36_IC::GetSysStatus0()
{
return eic->GetSysStatus0();
}
double ATM90E36_IC::GetSysStatus1()
{
return eic->GetSysStatus1();
}
double ATM90E36_IC::GetImportEnergy()
{
return eic->GetImportEnergy();
}
double ATM90E36_IC::GetExportEnergy()
{
return eic->GetExportEnergy();
}

@ -6,15 +6,35 @@ class ATM90E36_IC : public transformerEnergyMonitor {
private:
char ctLine;
int status;
public:
ATM90E36 *eic;
ATM90E36_IC(const char ctLineLetter, ATM90E36 ic);
void begin();
double GetLineVoltage();
double GetActivePower();
double GetSysStatus();
double GetPassivePower();
double GetMeterStatus0();
double GetMeterStatus1();
double GetSysStatus0();
double GetSysStatus1();
double GetTemperature();
double GetPhase();
double GetLineCurrent();
double GetLineCurrentN();
double GetApparentPower();
double GetPowerFactor();
double GetVHarm();
double GetCHarm();
double GetImportEnergy();
double GetExportEnergy();
};

@ -7,6 +7,9 @@
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[platformio]
default_envs = store-creds, dev
[env]
platform = espressif32
@ -25,7 +28,11 @@ lib_deps =
bblanchon/ArduinoJson @ ^6.21.3
paulstoffregen/OneWire@^2.3.8
milesburton/DallasTemperature@^3.11.0
build_src_filter = +<*> -<.git/> -<.svn/> -<tests/>
build_src_filter = +<transformerMonitor.cpp> -<.git/> -<.svn/> -<tests/>
[env:store-creds]
build_flags = -D DEV ${env.build_flags}
build_src_filter = -<*> +<store-config.cpp> -<.git/> -<.svn/> -<tests/>
[env:dev-ATM90E36]
build_flags = -D DEV ${env.build_flags}

@ -1,15 +1,27 @@
{
"time": "2021-05-04T13:13:04Z",
"volts": 120.00,
"amps": 600,
"deviceId": "esp32-blah-blah-random",
"time": 1351824120,
"voltage": 120,
"lineCurrent": 60,
"neutralLineCurrent": 60,
"meterStatus": 100,
"sysStatus": 60,
"energy": {
"export": 40,
"import": 40
},
"harmonics": {
"voltage": 6,
"current": 6
},
"power": {
"active": 90,
"passive": 8
"active": 6,
"apparent": 6,
"reactive": 6,
"factor": 60
},
"meterStatus": 60,
"id": "xformermon-random-data",
"temps": {
"oil": 70.0,
"cabinet": 60.0
"oil": 150,
"cabinet": 60
}
}

@ -0,0 +1,70 @@
#include <Preferences.h>
struct xformerMonConfigData {
char *wifiSsid;
char *wifiPass;
char *mqttName;
char *mqttServerHost;
char *mqttUserName;
char *mqttPassword;
uint16_t mqttServerPort;
};
// Turn build flags (Macros) into strings
#define ST(A) #A
#define STR(A) ST(A)
// extract the WiFi SSID from its macro
#ifdef TM_WIFI_SSID
char *wifiSsid = STR(TM_WIFI_SSID);
#endif
// extract the WiFi Password from its macro
#ifdef TM_WIFI_PASSWD
char *wifiPassword = STR(TM_WIFI_PASSWD);
#endif
// extract the MQTT Port from its macro
#ifdef TM_MQTT_PORT
uint16_t mqttPort = (uint16_t) strtoul(STR(TM_MQTT_PORT), NULL, 10);
#endif
// extract the MQTT server hostname from its macro
#ifdef TM_MQTT_SVR
char *mqttServer = STR(TM_MQTT_SVR);
#endif
// extract the MQTT username from its macro
#ifdef TM_MQTT_USER
char *mqttUser = STR(TM_MQTT_USER);
#endif
// extract the MQTT password from its macro
#ifdef TM_MQTT_PASSWD
char *mqttPass = STR(TM_MQTT_PASSWD);
#endif
Preferences preferences;
Preferences mqttPreferences;
xformerMonConfigData monitorConfig;
void setup() {
Serial.begin(115200);
Serial.println();
monitorConfig.wifiSsid = wifiSsid;
preferences.begin("wifi", false);
mqttPreferences.begin("mqtt", false);
preferences.putBytes("config", &monitorConfig, sizeof(monitorConfig));
preferences.putString("password", wifiPassword);
Serial.println("Network Credentials Saved using Preferences");
preferences.end();
}
void loop() {
}

@ -17,56 +17,54 @@ void setupEnergyMonitor();
// const char* test_client_cert = ""; //to verify the client
void setup()
{
eicDataQueue = xQueueCreate( 50, sizeof( xformerMonitorData ) );
// configure time
// TODO: make dst and timezone configurable
int timezone = 3;
int dst = 0;
configTime(timezone * 3600, dst * 0, "pool.ntp.org", "time.nist.gov");
// Initialize serial and wait for port to open:
Serial.begin(115200);
while (!Serial)
{
}
delay(20000);
delay(1000);
#ifdef TM_MQTT_SSL
wifiClient.setCACert(root_ca);
#endif
// Start the DS18B20 sensors
// monitorTempSensors.cabinet.begin();
// monitorTempSensors.oil.begin();
monitorTempSensors.cabinet.begin();
monitorTempSensors.oil.begin();
setupMQTTClient();
// Get each DS18B20 sensors' address
monitorTempSensors.oil.getAddress(oilTempSensorAddr, 0);
monitorTempSensors.cabinet.getAddress(cabinetTempSensorAddr, 0);
setupMQTTClient();
#ifdef ATM90E26_EIC
ATM90E26_IC eic;
#else
/* Initialize the serial port to host */
/*
The ATM90E36 has to be setup via SPI.
SPI for the ESP32:
- CLK: 18
- MISO: 19
- MOSI: 23
- CS: 5
*/
SPI.begin(SCK, MISO, MOSI, SS);
delay(1000);
eic.begin();
#endif
setupEnergyMonitor();
xTaskCreatePinnedToCore(
readEICData, /* Function to implement the task */
"Read EIC data", /* Name of the task */
10000, /* Stack size in words */
NULL, /* Task input parameter */
0, /* Priority of the task */
&taskReadEIC, /* Task handle. */
0); /* Core where the task should run */
xTaskCreatePinnedToCore(
sendSensorDataOverMQTT, /* Function to implement the task */
"Send sensor data over MQTT", /* Name of the task */
10000, /* Stack size in words */
NULL, /* Task input parameter */
0, /* Priority of the task */
&taskSendData, /* Task handle. */
1); /* Core where the task should run */
}
void connect()
{
// connect to the WiFi network
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
@ -101,7 +99,6 @@ void connect()
}
Serial.println("\nconnected!");
}
void messageReceived(String &topic, String &payload)
@ -116,53 +113,11 @@ void messageReceived(String &topic, String &payload)
void loop()
{
lastMillis = millis();
mqttClient.loop();
delay(10); // <- fixes some issues with WiFi stability
if (!mqttClient.connected())
{
connect();
}
// mqttClient.publish("xfmormermon", "buffer");
// // publish a message roughly every second.
if (millis() - lastMillis > 1000)
{
monitorTempSensors.cabinet.requestTemperatures();
monitorTempSensors.oil.requestTemperatures();
unsigned short volts = 121.2;
float cabinetTemperatureC = monitorTempSensors.cabinet.getTempCByIndex(0);
float cabinetTemperatureF = monitorTempSensors.cabinet.getTempFByIndex(0);
StaticJsonDocument<256> doc;
// Get the current time and store it in a variable
time_t now;
time(&now);
struct tm* timeinfo = gmtime(&now);
char timeBuffer[32];
strftime(timeBuffer, sizeof(timeBuffer), "%FT%TZ", timeinfo);
// set {"time":"2021-05-04T13:13:04Z"}
doc["time"] = timeBuffer;
doc["meterStatus"] = eic.GetLineVoltage();
// doc["meterStatus"] = 40;
doc["voltage"] = volts;
JsonObject temp = doc.createNestedObject("temps");
temp["cabinet"] = 40;
temp["oil"] = 70;
// temp["cabinet"] = monitorTempSensors.cabinet.getTempCByIndex(0);
// temp["oil"] = monitorTempSensors.oil.getTempCByIndex(0);
// dataStore->add(doc);
char mqttBuffer[256];
serializeJson(doc, mqttBuffer);
mqttClient.publish("xfomermon", mqttBuffer);
}
Serial.println("Sleeping 10s");
delay(10000);
}
@ -175,10 +130,135 @@ void setupMQTTClient()
mqttClient.setClient(wifiClient);
mqttClient.setServer(mqttServer, mqttPort);
mqttClient.setBufferSize(512);
}
// this function initializes the energy monitor
// depending on which monitor is used, the function will have call different functions
void setupEnergyMonitor()
{
#ifdef ATM90E26_EIC
ATM90E26_IC eic;
#else
/* Initialize the serial port to host */
/*
The ATM90E36 has to be setup via SPI.
SPI for the ESP32:
- CLK: 18
- MISO: 19
- MOSI: 23
- CS: 5
*/
SPI.begin(SCK, MISO, MOSI, SS);
delay(1000);
eic.begin();
#endif
}
// readEICData: reads the EIC and inserts data into queue
void readEICData(void *pvParameters)
{
Serial.print("Task1 running on core ");
Serial.println(xPortGetCoreID());
// Attach interrupt for reading data every one second
readEICTimer = timerBegin(0, 80, true);
timerAttachInterrupt(readEICTimer, &ReadData, true);
timerAlarmWrite(readEICTimer, 1000000, true);
timerAlarmEnable(readEICTimer); // Just Enable
for (;;)
{
}
}
// sendSensorDataOverMQTT: reads the EIC and inserts data into queue
void sendSensorDataOverMQTT(void *pvParameters)
{
Serial.print("Task1 running on core ");
Serial.println(xPortGetCoreID());
StaticJsonDocument<512> mqttJsonData;
JsonObject tempObj = mqttJsonData.createNestedObject("temps");
JsonObject powerObj = mqttJsonData.createNestedObject("power");
JsonObject energyObj = mqttJsonData.createNestedObject("energy");
xformerMonitorData mqttSensorData;
int messagesWaiting = uxQueueMessagesWaiting(eicDataQueue);
int emptySpaces = uxQueueSpacesAvailable(eicDataQueue);
for (;;)
{
if (messagesWaiting > 2)
{
xQueueReceive(eicDataQueue, &mqttSensorData, portMAX_DELAY);
char timeBuffer[32];
strftime(timeBuffer, sizeof(timeBuffer), "%FT%TZ", mqttSensorData.timeInfo);
mqttJsonData["deviceId"] = "esp32-random-id";
mqttJsonData["time"] = timeBuffer;
mqttJsonData["meterStatus"] = mqttSensorData.meterStatus;
mqttJsonData["sysStatus"] = mqttSensorData.sysStatus;
mqttJsonData["current"] = mqttSensorData.lineCurrent;
mqttJsonData["neutralCurrent"] = mqttSensorData.neutralCurrent;
mqttJsonData["voltage"] = mqttSensorData.lineCurrent;
powerObj["active"] = mqttSensorData.power.active;
powerObj["apparent"] = mqttSensorData.power.apparent;
powerObj["factor"] = mqttSensorData.power.factor;
powerObj["reactive"] = mqttSensorData.power.reactive;
tempObj["oil"] = mqttSensorData.temps.oil;
tempObj["cabinet"] = mqttSensorData.temps.cabinet;
energyObj["export"] = mqttSensorData.energy.exp;
energyObj["import"] = mqttSensorData.energy.import;
char buffer[256];
size_t n = serializeJson(mqttJsonData, buffer);
mqttClient.publish("xfmormermon/", buffer, n);
}
mqttClient.loop();
delay(10); // <- fixes some issues with WiFi stability
if (!mqttClient.connected())
{
connect();
}
messagesWaiting = uxQueueMessagesWaiting(eicDataQueue);
emptySpaces = uxQueueMessagesWaiting(eicDataQueue);
}
}
void IRAM_ATTR ReadData(){
// Count the number of times the ISR has been entered
static int timesEnteredISR = 1;
timesEnteredISR++;
// Read temperature data every 60 seconds
// Obtain DS18B20 sensor data
if (timesEnteredISR == 60)
{
timesEnteredISR = 0;
monitorTempSensors.cabinet.requestTemperatures();
monitorTempSensors.oil.requestTemperatures();
// get cabinet temp sensor data
sensorData.temps.cabinet = monitorTempSensors.cabinet.getTempC(cabinetTempSensorAddr);
// get oil temp sensor data
sensorData.temps.oil = monitorTempSensors.oil.getTempC(oilTempSensorAddr);
}
// Get the current time and store it in a variable
time(&now);
// set {"time":"2021-05-04T13:13:04Z"}
sensorData.timeInfo = gmtime(&now);
sensorData.lineVoltage = eic.GetLineVoltage();
sensorData.neutralCurrent = eic.GetLineCurrentN();
// sensorData.energy.exp =
xQueueSend(eicDataQueue, &sensorData, portMAX_DELAY);
}
Loading…
Cancel
Save