initial
This commit is contained in:
commit
66672c7808
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.pio
|
||||||
|
.vscode/.browse.c_cpp.db*
|
||||||
|
.vscode/c_cpp_properties.json
|
||||||
|
.vscode/launch.json
|
||||||
|
.vscode/ipch
|
||||||
|
/mqtt_ca.crt
|
28
include/common.h
Normal file
28
include/common.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#ifndef JANITZA104_ESP32_COMMON_H_
|
||||||
|
#define JANITZA104_ESP32_COMMON_H_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
|
||||||
|
#define PRINTLN(s) Serial.println(s)
|
||||||
|
#define PRINT(s) Serial.print(s)
|
||||||
|
#define PRINTF(fmt, ...) Serial.printf(fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
static void printWithPadding(String str, int totalLength);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define PRINTLN(s)
|
||||||
|
#define PRINT(s)
|
||||||
|
#define PRINTF(...)
|
||||||
|
#define printWithPadding(s, l)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
|
||||||
|
|
||||||
|
bool startsWith(const char* source, const char* prefix);
|
||||||
|
|
||||||
|
#endif //JANITZA104_ESP32_COMMON_H_
|
35
include/janitza.h
Normal file
35
include/janitza.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef JANITZA104_ESP32_JANITZA_H_
|
||||||
|
#define JANITZA104_ESP32_JANITZA_H_
|
||||||
|
|
||||||
|
#include <ModbusMaster.h>
|
||||||
|
|
||||||
|
enum class JanitzaType { FLOAT, LONG64, INT, SHORT };
|
||||||
|
enum class JanitzaUnit { V, A, W, VA, Wh };
|
||||||
|
|
||||||
|
struct JanitzaRegister {
|
||||||
|
uint16_t addr;
|
||||||
|
JanitzaType type;
|
||||||
|
JanitzaUnit unit;
|
||||||
|
const char* name;
|
||||||
|
const char* desc;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class JanitzaReader {
|
||||||
|
private:
|
||||||
|
ModbusMaster node;
|
||||||
|
uint8_t lastErrorCode = 0;
|
||||||
|
|
||||||
|
static void modbusPreTransmissionCallback();
|
||||||
|
static void modbusPostTransmissionCallback();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void configure();
|
||||||
|
bool readFloat(const JanitzaRegister& reg, float* val);
|
||||||
|
uint8_t getLastErrorCode() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const char* JanitzaUnitStr(JanitzaUnit unit);
|
||||||
|
|
||||||
|
#endif //JANITZA104_ESP32_JANITZA_H_
|
26
include/led.h
Normal file
26
include/led.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef JANITZA104_ESP32_LED_H_
|
||||||
|
#define JANITZA104_ESP32_LED_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class Led {
|
||||||
|
private:
|
||||||
|
uint8_t _pin;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Led(uint8_t pin) : _pin(pin) {
|
||||||
|
pinMode(_pin, OUTPUT);
|
||||||
|
off();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void off() const { digitalWrite(_pin, HIGH); }
|
||||||
|
inline void on() const { digitalWrite(_pin, LOW); }
|
||||||
|
|
||||||
|
void on_off(uint16_t delay_ms, bool last_delay = false) const;
|
||||||
|
void blink(uint8_t count, uint16_t delay_ms) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const Led* mcu_led;
|
||||||
|
|
||||||
|
#endif //JANITZA104_ESP32_LED_H_
|
71
mqtt_monitor.sh
Executable file
71
mqtt_monitor.sh
Executable file
@ -0,0 +1,71 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "usage: $0 [-h|--help] [-t <topic>]" >&2
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
die() {
|
||||||
|
echo "error: $1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
check_command() {
|
||||||
|
if ! command -v "$1" >/dev/null; then
|
||||||
|
die "$1 is not installed. Please install $1 to proceed."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_yaml() {
|
||||||
|
if ! yaml_output=$(yq -r "$1" "$2" 2>/dev/null); then
|
||||||
|
die "YAML file is malformed or does not exist."
|
||||||
|
fi
|
||||||
|
echo "$yaml_output"
|
||||||
|
}
|
||||||
|
|
||||||
|
for c in yq mosquitto_sub tput; do check_command $c; done
|
||||||
|
|
||||||
|
[ -z "$1" ] && usage
|
||||||
|
|
||||||
|
bold=$(tput bold)
|
||||||
|
rst=$(tput sgr0)
|
||||||
|
topic=
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-t|--topic)
|
||||||
|
topic="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*) ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -z "$topic" ] && die "Topic not provided. Use -t or --topic to specify the topic."
|
||||||
|
|
||||||
|
remote_host="mqtt.example.org"
|
||||||
|
remote_port=8883
|
||||||
|
username="admin"
|
||||||
|
password="password"
|
||||||
|
|
||||||
|
mydir=$(dirname "$0")
|
||||||
|
cafile="$mydir/mqtt_ca.crt"
|
||||||
|
topic_regex="${topic%#}"
|
||||||
|
topic_regex="${topic_regex//\//\\/}"
|
||||||
|
|
||||||
|
echo mosquitto_sub -d -h "$remote_host" -p "$remote_port" --cafile "$cafile" -t "$topic" -u "$username" -P "$password" -v
|
||||||
|
|
||||||
|
mosquitto_sub -d -h "$remote_host" -p "$remote_port" --cafile "$cafile" -t "$topic" -u "$username" -P "$password" -v | while IFS= read -r line; do
|
||||||
|
binary_data="$(echo "$line" | sed "s/^${topic_regex}[^ ]* //")"
|
||||||
|
echo -n "${bold}$(echo "$line" | awk '{print $1}')${rst}"
|
||||||
|
echo -n " "
|
||||||
|
echo -n "$binary_data" | xxd -p | tr -d '\n' | sed 's/../& /g'
|
||||||
|
echo
|
||||||
|
# echo
|
||||||
|
done
|
35
platformio.ini
Normal file
35
platformio.ini
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
; 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:denky32]
|
||||||
|
platform = espressif32
|
||||||
|
board = esp32dev
|
||||||
|
framework = arduino
|
||||||
|
lib_deps =
|
||||||
|
4-20ma/ModbusMaster@^2.0.1
|
||||||
|
knolleary/PubSubClient@^2.8
|
||||||
|
monitor_speed = 115200
|
||||||
|
build_flags =
|
||||||
|
-DCONFIG_FW_VERSION=1
|
||||||
|
-DCONFIG_MCU_LED_GPIO=2
|
||||||
|
-DCONFIG_JANITZA_EMULATE=1
|
||||||
|
-DCONFIG_JANITZA_EMULATE_ERROR=0
|
||||||
|
-DCONFIG_MODBUS_DIR_PIN=4
|
||||||
|
-DCONFIG_MODBUS_RX_PIN=18
|
||||||
|
-DCONFIG_MODBUS_TX_PIN=19
|
||||||
|
-DCONFIG_MODBUS_SLAVE_ID=1
|
||||||
|
-DCONFIG_MODBUS_SERIAL_BAUD=9600
|
||||||
|
-DCONFIG_MQTT_SERVER="\"mqtt.example.org\""
|
||||||
|
-DCONFIG_MQTT_PORT=8883
|
||||||
|
-DCONFIG_MQTT_USERNAME="\"username\""
|
||||||
|
-DCONFIG_MQTT_PASSWORD="\"password\""
|
||||||
|
-DCONFIG_WIFI_HOSTNAME="\"ESP_J104R_0001\""
|
||||||
|
-DCONFIG_NODE_ID=0
|
||||||
|
build_type = release
|
22
src/common.cpp
Normal file
22
src/common.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
|
||||||
|
void printWithPadding(String str, int totalLength) {
|
||||||
|
int paddingLength = totalLength - str.length();
|
||||||
|
Serial.print(str);
|
||||||
|
for (int i = 0; i < paddingLength; i++) {
|
||||||
|
Serial.print(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool startsWith(const char* source, const char* prefix) {
|
||||||
|
while (*prefix) {
|
||||||
|
if (*source != *prefix) return false;
|
||||||
|
source++;
|
||||||
|
prefix++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
91
src/janitza.cpp
Normal file
91
src/janitza.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include "janitza.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define MODBUS_TRANSMISSION_DELAY 2
|
||||||
|
|
||||||
|
const char* JanitzaUnitStr(JanitzaUnit unit) {
|
||||||
|
switch (unit) {
|
||||||
|
case JanitzaUnit::V: return "V";
|
||||||
|
case JanitzaUnit::A: return "A";
|
||||||
|
case JanitzaUnit::W: return "W";
|
||||||
|
case JanitzaUnit::VA: return "VA";
|
||||||
|
case JanitzaUnit::Wh: return "Wh";
|
||||||
|
default: return "[?]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JanitzaReader::configure() {
|
||||||
|
#ifndef CONFIG_JANITZA_EMULATE
|
||||||
|
pinMode(CONFIG_MODBUS_DIR_PIN, OUTPUT);
|
||||||
|
digitalWrite(CONFIG_MODBUS_DIR_PIN, LOW);
|
||||||
|
|
||||||
|
Serial2.begin(CONFIG_MODBUS_SERIAL_BAUD, SERIAL_8N1, CONFIG_MODBUS_RX_PIN, CONFIG_MODBUS_TX_PIN);
|
||||||
|
Serial2.setTimeout(200);
|
||||||
|
node.begin(CONFIG_MODBUS_SLAVE_ID, Serial2);
|
||||||
|
|
||||||
|
node.preTransmission(JanitzaReader::modbusPreTransmissionCallback);
|
||||||
|
node.postTransmission(JanitzaReader::modbusPostTransmissionCallback);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void JanitzaReader::modbusPreTransmissionCallback() {
|
||||||
|
#ifndef CONFIG_JANITZA_EMULATE
|
||||||
|
delay(MODBUS_TRANSMISSION_DELAY);
|
||||||
|
digitalWrite(CONFIG_MODBUS_DIR_PIN, HIGH);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void JanitzaReader::modbusPostTransmissionCallback() {
|
||||||
|
#ifndef CONFIG_JANITZA_EMULATE
|
||||||
|
digitalWrite(CONFIG_MODBUS_DIR_PIN, LOW);
|
||||||
|
delay(MODBUS_TRANSMISSION_DELAY);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JanitzaReader::readFloat(const JanitzaRegister& reg, float* val) {
|
||||||
|
#ifndef CONFIG_JANITZA_EMULATE
|
||||||
|
uint8_t result;
|
||||||
|
uint16_t buf[2];
|
||||||
|
|
||||||
|
result = node.readInputRegisters(reg.addr, 2);
|
||||||
|
if (result == node.ku8MBSuccess) {
|
||||||
|
buf[1] = node.getResponseBuffer(0x00);
|
||||||
|
buf[0] = node.getResponseBuffer(0x01);
|
||||||
|
*val = *((float*)buf);
|
||||||
|
PRINTF("JanitzaReader: %s = %.2f\n", reg->name, val);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
lastErrorCode = result;
|
||||||
|
PRINTF("JanitzaReader: failed to read %d, device response: %d\n", reg.addr, result);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#if CONFIG_JANITZA_EMULATE_ERROR == 1
|
||||||
|
PRINTLN("JanitzaReader: emulation read error");
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (startsWith(reg.name, "_ULN") || startsWith(reg.name, "_ULN")) {
|
||||||
|
*val = 220.0f;
|
||||||
|
} else if (startsWith(reg.name, "_ILN")) {
|
||||||
|
*val = 5.0f;
|
||||||
|
} else if (startsWith(reg.name, "_I_SUM3")) {
|
||||||
|
*val = 15.0f;
|
||||||
|
} else if (startsWith(reg.name, "_PLN")) {
|
||||||
|
*val = 100.0f;
|
||||||
|
} else if (!strcmp(reg.name, "_P_SUM3")) {
|
||||||
|
*val = 250.0f;
|
||||||
|
} else if (startsWith(reg.name, "_SLN")) {
|
||||||
|
*val = 400.0f;
|
||||||
|
} else if (startsWith(reg.name, "_WH")) {
|
||||||
|
*val = 450.0f;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t JanitzaReader::getLastErrorCode() const {
|
||||||
|
return lastErrorCode;
|
||||||
|
}
|
18
src/led.cpp
Normal file
18
src/led.cpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include "led.h"
|
||||||
|
|
||||||
|
void Led::on_off(uint16_t delay_ms, bool last_delay) const {
|
||||||
|
on();
|
||||||
|
delay(delay_ms);
|
||||||
|
|
||||||
|
off();
|
||||||
|
if (last_delay)
|
||||||
|
delay(delay_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Led::blink(uint8_t count, uint16_t delay_ms) const {
|
||||||
|
for (uint8_t i = 0; i < count; i++) {
|
||||||
|
on_off(delay_ms, i < count-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Led* mcu_led = new Led(CONFIG_MCU_LED_GPIO);
|
300
src/main.cpp
Normal file
300
src/main.cpp
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <PubSubClient.h>
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <time.h>
|
||||||
|
#include "janitza.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "led.h"
|
||||||
|
|
||||||
|
#define MQTT_RECONNECT_SECONDS 3
|
||||||
|
#define LOOP_DELAY 500
|
||||||
|
#define READ_FREQ 5000
|
||||||
|
|
||||||
|
#define CONFIG_WIFI_SSID "ssid"
|
||||||
|
#define CONFIG_WIFI_PSK "11112222"
|
||||||
|
|
||||||
|
// Certificate
|
||||||
|
const char* mqttRootCA = \
|
||||||
|
"-----BEGIN CERTIFICATE-----\n" \
|
||||||
|
...
|
||||||
|
"-----END CERTIFICATE-----";
|
||||||
|
|
||||||
|
const char* mqttServer = CONFIG_MQTT_SERVER;
|
||||||
|
const char* mqttUserName = CONFIG_MQTT_USERNAME;
|
||||||
|
const char* mqttPassword = CONFIG_MQTT_PASSWORD;
|
||||||
|
|
||||||
|
static JanitzaRegister umg104_registers[] = {
|
||||||
|
{19000, JanitzaType::FLOAT, JanitzaUnit::V, "_ULN[0]", "Voltage L1-N"},
|
||||||
|
{19002, JanitzaType::FLOAT, JanitzaUnit::V, "_ULN[1]", "Voltage L2-N"},
|
||||||
|
{19004, JanitzaType::FLOAT, JanitzaUnit::V, "_ULN[2]", "Voltage L3-N"},
|
||||||
|
|
||||||
|
{19006, JanitzaType::FLOAT, JanitzaUnit::V, "_ULL[0]", "Voltage L1-L2"},
|
||||||
|
{19008, JanitzaType::FLOAT, JanitzaUnit::V, "_ULL[1]", "Voltage L2-L3"},
|
||||||
|
{19010, JanitzaType::FLOAT, JanitzaUnit::V, "_ULL[2]", "Voltage L3-L1"},
|
||||||
|
|
||||||
|
{19012, JanitzaType::FLOAT, JanitzaUnit::A, "_ILN[0]", "Apparent current L1"},
|
||||||
|
{19014, JanitzaType::FLOAT, JanitzaUnit::A, "_ILN[1]", "Apparent current L2"},
|
||||||
|
{19016, JanitzaType::FLOAT, JanitzaUnit::A, "_ILN[2]", "Apparent current L3"},
|
||||||
|
|
||||||
|
{19018, JanitzaType::FLOAT, JanitzaUnit::A, "_I_SUM3", "Vector sum; IN=I1+I2+I3"},
|
||||||
|
{19026, JanitzaType::FLOAT, JanitzaUnit::W, "_P_SUM3", "Sum; Psum3=P1+P2+P3"},
|
||||||
|
|
||||||
|
{19020, JanitzaType::FLOAT, JanitzaUnit::W, "_PLN[0]", "Real power L1"},
|
||||||
|
{19022, JanitzaType::FLOAT, JanitzaUnit::W, "_PLN[1]", "Real power L2"},
|
||||||
|
{19024, JanitzaType::FLOAT, JanitzaUnit::W, "_PLN[2]", "Real power L3"},
|
||||||
|
|
||||||
|
{19028, JanitzaType::FLOAT, JanitzaUnit::VA, "_SLN[0]", "Apparent power L1"},
|
||||||
|
{19030, JanitzaType::FLOAT, JanitzaUnit::VA, "_SLN[1]", "Apparent power L2"},
|
||||||
|
{19032, JanitzaType::FLOAT, JanitzaUnit::VA, "_SLN[2]", "Apparent power L3"},
|
||||||
|
|
||||||
|
{19054, JanitzaType::FLOAT, JanitzaUnit::Wh, "_WH[0]", "Real energy L1"},
|
||||||
|
{19056, JanitzaType::FLOAT, JanitzaUnit::Wh, "_WH[1]", "Real energy L2"},
|
||||||
|
{19058, JanitzaType::FLOAT, JanitzaUnit::Wh, "_WH[2]", "Real energy L3"}
|
||||||
|
};
|
||||||
|
|
||||||
|
static WiFiClientSecure espClient;
|
||||||
|
static PubSubClient mqtt(espClient);
|
||||||
|
|
||||||
|
static JanitzaReader jr;
|
||||||
|
|
||||||
|
static const char* MqttHelloTopic = "slrmn/%d/hello";
|
||||||
|
static const char* MqttOtaTopic = "slrmn/%d/ota";
|
||||||
|
static const char* MqttEnergyTopic = "slrmn/%d/energy";
|
||||||
|
static const char* MqttErrorTopic = "slrmn/%d/error";
|
||||||
|
|
||||||
|
struct __attribute__((__packed__)) MqttEnergyDataPayload {
|
||||||
|
float uln0;
|
||||||
|
float uln1;
|
||||||
|
float uln2;
|
||||||
|
|
||||||
|
float ull0;
|
||||||
|
float ull1;
|
||||||
|
float ull2;
|
||||||
|
|
||||||
|
float iln0;
|
||||||
|
float iln1;
|
||||||
|
float iln2;
|
||||||
|
|
||||||
|
float i_sum3;
|
||||||
|
float p_sum3;
|
||||||
|
|
||||||
|
float pln0;
|
||||||
|
float pln1;
|
||||||
|
float pln2;
|
||||||
|
|
||||||
|
float sln0;
|
||||||
|
float sln1;
|
||||||
|
float sln2;
|
||||||
|
|
||||||
|
float wh0;
|
||||||
|
float wh1;
|
||||||
|
float wh2;
|
||||||
|
|
||||||
|
uint32_t timestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct __attribute__((__packed__)) MqttErrorPayload {
|
||||||
|
uint32_t timestamp;
|
||||||
|
uint16_t addr;
|
||||||
|
uint8_t code;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct __attribute__((__packed__)) MqttHelloPayload {
|
||||||
|
uint32_t timestamp;
|
||||||
|
uint16_t fw_version;
|
||||||
|
};
|
||||||
|
|
||||||
|
static volatile bool mqttNeedsReconnect = true;
|
||||||
|
static bool timeConfigured = false;
|
||||||
|
static bool wifiConnectionCalled = false;
|
||||||
|
// static bool wifiOnceConnected = false;
|
||||||
|
|
||||||
|
static long lastNTPCheck = 0;
|
||||||
|
static long lastJanitraRead = 0;
|
||||||
|
static long lastMqttReconnectAttempt = 0;
|
||||||
|
static long wifiReconnectStarted = 0;
|
||||||
|
|
||||||
|
static void WiFiStationConnected(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||||
|
static void WiFiStationDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||||
|
|
||||||
|
static void mqttReconnect();
|
||||||
|
static void mqttCallback(char* topic, uint8_t* payload, size_t length);
|
||||||
|
static void getTopicName(char* buf, size_t size, const char* fmt);
|
||||||
|
static String strgen(int length);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.begin(115200);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_JANITZA_EMULATE
|
||||||
|
jr.configure();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
WiFi.begin(CONFIG_WIFI_SSID, CONFIG_WIFI_PSK);
|
||||||
|
WiFi.setAutoReconnect(true);
|
||||||
|
WiFi.hostname(CONFIG_WIFI_HOSTNAME);
|
||||||
|
|
||||||
|
espClient.setCACert(mqttRootCA);
|
||||||
|
// espClient.setInsecure();
|
||||||
|
|
||||||
|
wifiConnectionCalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
auto ws = WiFi.status();
|
||||||
|
if (ws != WL_CONNECTED) {
|
||||||
|
if (wifiReconnectStarted > 0 && millis() - wifiReconnectStarted > 60000) {
|
||||||
|
PRINTF("\nfailed to reconnect, restarting...\n");
|
||||||
|
ESP.restart();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!wifiConnectionCalled) {
|
||||||
|
PRINT("Connecting to wifi..");
|
||||||
|
// WiFi.setAutoReconnect(true);
|
||||||
|
WiFi.disconnect();
|
||||||
|
WiFi.reconnect();
|
||||||
|
wifiConnectionCalled = true;
|
||||||
|
wifiReconnectStarted = millis();
|
||||||
|
}
|
||||||
|
PRINT(".");
|
||||||
|
mcu_led->blink(2, 50);
|
||||||
|
delay(LOOP_DELAY);
|
||||||
|
mqttNeedsReconnect = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wifiConnectionCalled = false;
|
||||||
|
|
||||||
|
if (!timeConfigured) {
|
||||||
|
randomSeed(micros());
|
||||||
|
|
||||||
|
configTime(3600*3, 0, "pool.ntp.org", "ntp0.ntp-servers.net", "ntp4.ntp-servers.net");
|
||||||
|
timeConfigured = true;
|
||||||
|
|
||||||
|
PRINTLN("Waiting for time");
|
||||||
|
while (time(nullptr) < 24 * 3600) {
|
||||||
|
PRINT(".");
|
||||||
|
delay(LOOP_DELAY);
|
||||||
|
}
|
||||||
|
PRINTLN("");
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t timestamp = time(nullptr);
|
||||||
|
|
||||||
|
long now = millis();
|
||||||
|
long delaytime = LOOP_DELAY;
|
||||||
|
bool firstTimeFetch = lastNTPCheck == 0;
|
||||||
|
|
||||||
|
int mqttState = mqtt.state();
|
||||||
|
if (!mqtt.connected() && (mqttNeedsReconnect && (!lastMqttReconnectAttempt || now-lastMqttReconnectAttempt > MQTT_RECONNECT_SECONDS*1000)) || mqttState < 0)
|
||||||
|
mqttReconnect();
|
||||||
|
|
||||||
|
if (mqtt.connected()) {
|
||||||
|
mqtt.loop();
|
||||||
|
|
||||||
|
if (!lastJanitraRead || now-lastJanitraRead > READ_FREQ) {
|
||||||
|
uint16_t buf[2];
|
||||||
|
char topic[32];
|
||||||
|
float val;
|
||||||
|
|
||||||
|
uint16_t failedAddr = 0;
|
||||||
|
uint8_t failedCode = 0;
|
||||||
|
uint32_t ts = timestamp;
|
||||||
|
|
||||||
|
MqttEnergyDataPayload energyPayload;
|
||||||
|
energyPayload.timestamp = ts;
|
||||||
|
|
||||||
|
JanitzaRegister* reg;
|
||||||
|
for (int i = 0; i < ARRAY_SIZE(umg104_registers); i++) {
|
||||||
|
reg = &umg104_registers[i];
|
||||||
|
if (!jr.readFloat(*reg, &val)) {
|
||||||
|
failedCode = jr.getLastErrorCode();
|
||||||
|
failedAddr = reg->addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(*(float*)((uint8_t*)&energyPayload + sizeof(float)*i)) = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failedAddr != 0) {
|
||||||
|
MqttErrorPayload errorPayload = {
|
||||||
|
.timestamp = ts,
|
||||||
|
.addr = failedAddr,
|
||||||
|
.code = failedCode
|
||||||
|
};
|
||||||
|
|
||||||
|
getTopicName(topic, sizeof(topic), MqttErrorTopic);
|
||||||
|
mqtt.publish(topic, (uint8_t*)&errorPayload, sizeof(errorPayload));
|
||||||
|
} else {
|
||||||
|
getTopicName(topic, sizeof(topic), MqttEnergyTopic);
|
||||||
|
mqtt.publish(topic, (uint8_t*)&energyPayload, sizeof(energyPayload));
|
||||||
|
}
|
||||||
|
|
||||||
|
lastJanitraRead = now;
|
||||||
|
} else {
|
||||||
|
long timedelta = READ_FREQ - (now - lastJanitraRead);
|
||||||
|
delaytime = timedelta > LOOP_DELAY ? LOOP_DELAY : timedelta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRINTLN(timestamp);
|
||||||
|
delay(delaytime);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mqttCallback(char* topic, uint8_t* payload, size_t length) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mqttReconnect() {
|
||||||
|
char buf[32];
|
||||||
|
long now = millis();
|
||||||
|
mqttNeedsReconnect = false;
|
||||||
|
lastMqttReconnectAttempt = now;
|
||||||
|
mqtt.setBufferSize(1024);
|
||||||
|
mqtt.setServer(mqttServer, CONFIG_MQTT_PORT);
|
||||||
|
String clientId = String(CONFIG_WIFI_HOSTNAME) + "_" + strgen(4);
|
||||||
|
PRINTF("mqtt client id will be %s\n", clientId.c_str());
|
||||||
|
if (mqtt.connect(clientId.c_str(), mqttUserName, mqttPassword)) {
|
||||||
|
PRINTLN("mqtt: connected [1]");
|
||||||
|
mqtt.loop();
|
||||||
|
mqtt.setCallback(mqttCallback);
|
||||||
|
|
||||||
|
// subscribe to the OTA topic
|
||||||
|
getTopicName(buf, sizeof(buf), MqttOtaTopic);
|
||||||
|
mqtt.subscribe(buf);
|
||||||
|
|
||||||
|
// send hello payl
|
||||||
|
getTopicName(buf, sizeof(buf), MqttHelloTopic);
|
||||||
|
auto payload = MqttHelloPayload {
|
||||||
|
.timestamp = static_cast<uint32_t>(time(nullptr)),
|
||||||
|
.fw_version = CONFIG_FW_VERSION
|
||||||
|
};
|
||||||
|
mqtt.publish(buf, (uint8_t*)&payload, sizeof(payload));
|
||||||
|
|
||||||
|
PRINTLN("mqtt: connected [2]");
|
||||||
|
lastMqttReconnectAttempt = 0;
|
||||||
|
} else {
|
||||||
|
PRINTF("mqtt: failed to connect, rc=%d, retrying in %d seconds\n",
|
||||||
|
mqtt.state(), MQTT_RECONNECT_SECONDS);
|
||||||
|
mqttNeedsReconnect = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void getTopicName(char* buf, size_t size, const char* fmt) {
|
||||||
|
memset(buf, 0, size);
|
||||||
|
snprintf(buf, size-1, fmt, CONFIG_NODE_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String strgen(int length) {
|
||||||
|
String randomString = "";
|
||||||
|
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
int index = random(characters.length());
|
||||||
|
char nextChar = characters.charAt(index);
|
||||||
|
randomString += nextChar;
|
||||||
|
}
|
||||||
|
return randomString;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user