Work on NMEA2000 device list
This commit is contained in:
157
src/main.cpp
157
src/main.cpp
@@ -4,6 +4,7 @@
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <Update.h>
|
||||
#include <Wire.h>
|
||||
#include <SHT31.h> // temp. sensor
|
||||
#include <NMEA2000.h>
|
||||
@@ -11,6 +12,7 @@
|
||||
#include <N2kMessages.h>
|
||||
#include "main.h"
|
||||
#include "Nmea2kTwai.h"
|
||||
#include "N2kDeviceList.h"
|
||||
#include <map>
|
||||
|
||||
#include "mbedtls/md.h" // for SHA256
|
||||
@@ -112,6 +114,7 @@ uint8_t rgb_brightness = 64;
|
||||
uint buzzerpower = 50; // TBD make use of this
|
||||
|
||||
uint8_t keycode[6]; // configurable keycodes
|
||||
uint8_t longcode[6]; // configurable keycodes for long pressed keys
|
||||
|
||||
SHT31 sht(SHT31_ADDRESS);
|
||||
bool sht_available = false;
|
||||
@@ -120,7 +123,7 @@ float hum = 0.0;
|
||||
|
||||
int nodeid; // NMEA2000 id on bus
|
||||
Nmea2kTwai &NMEA2000=*(new Nmea2kTwai(CAN_TX, CAN_RX, CAN_RECOVERY_PERIOD));
|
||||
|
||||
tN2kDeviceList *pN2kDeviceList;
|
||||
|
||||
String processor(const String& var) {
|
||||
// dummy for now
|
||||
@@ -300,6 +303,12 @@ void setup() {
|
||||
keycode[3] = preferences.getInt("key4", 4);
|
||||
keycode[4] = preferences.getInt("key5", 5);
|
||||
keycode[5] = preferences.getInt("key6", 6);
|
||||
longcode[0] = preferences.getInt("key1long", 11);
|
||||
longcode[1] = preferences.getInt("key2long", 12);
|
||||
longcode[2] = preferences.getInt("key3long", 13);
|
||||
longcode[3] = preferences.getInt("key4long", 14);
|
||||
longcode[4] = preferences.getInt("key5long", 15);
|
||||
longcode[5] = preferences.getInt("key6long", 16);
|
||||
preferences.end();
|
||||
|
||||
// Configure I/O pins
|
||||
@@ -404,6 +413,31 @@ void setup() {
|
||||
serializeJson(doc, out);
|
||||
request->send(200, "application/json", out);
|
||||
});
|
||||
server.on("/api/devicelist", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
// NMEA2000 device list
|
||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||
response->print("[");
|
||||
bool first = true;
|
||||
for (int i = 0; i <= 252; i++) {
|
||||
const tNMEA2000::tDevice *d = pN2kDeviceList->FindDeviceBySource(i);
|
||||
if (d == nullptr) {
|
||||
continue;
|
||||
}
|
||||
uint64_t NAME = d->GetName();
|
||||
char hex_name[17];
|
||||
snprintf(hex_name, sizeof(hex_name), "%08X%08X", (uint32_t)(NAME >> 32), (uint32_t)(NAME & 0xFFFFFFFF));
|
||||
if (!first) {
|
||||
response->print(",");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
// TODO last seen?
|
||||
response->printf("{\"source\":%d,\"name\":\"%s\",\"manuf\":\"%d\",\"model\":\"%s\"}",
|
||||
i, hex_name, d->GetManufacturerCode(), d->GetModelID());
|
||||
}
|
||||
response->print("]");
|
||||
request->send(response);
|
||||
});
|
||||
server.on("/api/config", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
StaticJsonDocument<512> doc;
|
||||
doc["systemName"] = "Keypad1";
|
||||
@@ -428,6 +462,13 @@ void setup() {
|
||||
doc["key4"] = keycode[BUTTON_4];
|
||||
doc["key5"] = keycode[BUTTON_5];
|
||||
doc["key6"] = keycode[BUTTON_6];
|
||||
doc["key1long"] = longcode[BUTTON_1];
|
||||
doc["key2long"] = longcode[BUTTON_2];
|
||||
doc["key3long"] = longcode[BUTTON_3];
|
||||
doc["key4long"] = longcode[BUTTON_4];
|
||||
doc["key5long"] = longcode[BUTTON_5];
|
||||
doc["key6long"] = longcode[BUTTON_6];
|
||||
doc["envInterval"] = 5;
|
||||
String out;
|
||||
serializeJson(doc, out);
|
||||
request->send(200, "application/json", out);
|
||||
@@ -466,11 +507,33 @@ void setup() {
|
||||
request->send(200, "application/json", out);
|
||||
});
|
||||
server.on("/api/update", HTTP_POST, [](AsyncWebServerRequest *request){
|
||||
// the request handler is triggered after the upload has finished...
|
||||
// create the response, add header, and send response
|
||||
|
||||
StaticJsonDocument<100> doc;
|
||||
doc["status"] = "FAILED";
|
||||
String out;
|
||||
serializeJson(doc, out);
|
||||
request->send(200, "application/json", out);
|
||||
}, [](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
|
||||
// this is the new image upload part
|
||||
Serial.print("Retrieving firmware image named: ");
|
||||
Serial.println(filename);
|
||||
|
||||
if (index == 0) {
|
||||
if (! Update.begin(UPDATE_SIZE_UNKNOWN)) {
|
||||
Update.printError(Serial);
|
||||
}
|
||||
}
|
||||
if (Update.write(data, len) != len) {
|
||||
Update.printError(Serial);
|
||||
}
|
||||
if (final) {
|
||||
if (!Update.end(true)) {
|
||||
Update.printError(Serial);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// TODO POST vom Client entgegennehmen
|
||||
@@ -501,21 +564,31 @@ void setup() {
|
||||
4 // Industrygoup=Marine
|
||||
);
|
||||
|
||||
NMEA2000.SetForwardType(tNMEA2000::fwdt_Text);
|
||||
|
||||
// Debug
|
||||
// Debug Start
|
||||
// NMEA2000.SetForwardStream(&Serial);
|
||||
// NMEA2000.SetForwardType(tNMEA2000::fwdt_Text);
|
||||
// NMEA2000.SetForwardOwnMessages(true);
|
||||
// NMEA2000.SetDebugMode(tNMEA2000::dm_2);
|
||||
// Debug End
|
||||
|
||||
NMEA2000.SetMode(tNMEA2000::N2km_ListenAndNode, nodeid);
|
||||
//TODO: N2km_NodeOnly N2km_ListenAndNode?
|
||||
NMEA2000.SetMode(tNMEA2000::N2km_ListenAndNode, nodeid);
|
||||
NMEA2000.SetForwardOwnMessages(false);
|
||||
NMEA2000.SetHeartbeatIntervalAndOffset(NMEA2000_HEARTBEAT_INTERVAL);
|
||||
|
||||
const unsigned long TransmitPGNs[] = {
|
||||
127502UL,
|
||||
// Features?
|
||||
// 130311 environment
|
||||
// 130316 temperature extended range
|
||||
const unsigned long TransmitPGNs[] PROGMEM= {
|
||||
127502UL, // switch bank control
|
||||
130312UL, // temperature
|
||||
130313UL, // humidity
|
||||
0
|
||||
};
|
||||
NMEA2000.ExtendTransmitMessages(TransmitPGNs);
|
||||
pN2kDeviceList = new tN2kDeviceList(&NMEA2000);
|
||||
// Debug: NMEA2000.EnableForward(true);
|
||||
NMEA2000.Open();
|
||||
|
||||
// internal user led (red)
|
||||
@@ -618,6 +691,41 @@ void atariKeyclick() {
|
||||
ledcWriteTone(LEDC_CHANNEL, 0);
|
||||
}
|
||||
|
||||
void print_n2k_devicelist() {
|
||||
if (!pN2kDeviceList) {
|
||||
Serial.println("Devicelist not initialized");
|
||||
}
|
||||
if (!pN2kDeviceList->ReadResetIsListUpdated()) {
|
||||
// no changes, nothing to do
|
||||
Serial.println("Devicelist empty or unchanged");
|
||||
return;
|
||||
}
|
||||
Serial.println("---- NMEA2000 Device List ----");
|
||||
|
||||
for (int i = 0; i <= 252; i++) {
|
||||
const tNMEA2000::tDevice *d = pN2kDeviceList->FindDeviceBySource(i);
|
||||
if (d == nullptr) {
|
||||
continue;
|
||||
}
|
||||
// age in milliseconds
|
||||
unsigned long lastseen = pN2kDeviceList->GetDeviceLastMessageTime(i);
|
||||
Serial.printf("Device %d age %d ms\n", i, lastseen);
|
||||
uint64_t NAME = d->GetName();
|
||||
char hex_name[17];
|
||||
snprintf(hex_name, sizeof(hex_name), "%08X%08X",
|
||||
(uint32_t)(NAME >> 32), (uint32_t)(NAME & 0xFFFFFFFF));
|
||||
Serial.printf("Src:%d Man:%d Model:%s (0x%s)\n",
|
||||
d->GetSource(),
|
||||
d->GetManufacturerCode(),
|
||||
d->GetModelID(),
|
||||
hex_name
|
||||
);
|
||||
}
|
||||
|
||||
Serial.println("------------------------------");
|
||||
}
|
||||
|
||||
// rename to: void sendSwitchBank()
|
||||
void SendToN2K(uint8_t keycode) {
|
||||
tN2kMsg N2kMsg;
|
||||
tN2kBinaryStatus bankstatus;
|
||||
@@ -636,6 +744,20 @@ void SendToN2K(uint8_t keycode) {
|
||||
Serial.println(" Action=On");
|
||||
}
|
||||
|
||||
void send_sensor_temphum(float temp_k, float hum_perc) {
|
||||
tN2kMsg N2kMsg;
|
||||
static unsigned char SID = 0;
|
||||
unsigned char instance = 0;
|
||||
tN2kTempSource temp_src = N2kts_OutsideTemperature; // 1=outside, 2=inside
|
||||
tN2kHumiditySource hum_src = N2khs_OutsideHumidity; // 0=inside, 1=outside
|
||||
Serial.printf("Sending temp=%f K, hum=%f %%\n", temp_k, hum_perc);
|
||||
SetN2kPGN130312(N2kMsg, SID, instance, temp_src, temp_k);
|
||||
NMEA2000.SendMsg(N2kMsg);
|
||||
SetN2kPGN130313(N2kMsg, SID, instance, hum_src, hum_perc);
|
||||
NMEA2000.SendMsg(N2kMsg);
|
||||
SID = (SID + 1) % 256;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
ButtonEvent event;
|
||||
@@ -684,17 +806,29 @@ void loop() {
|
||||
if (mode == 'N') {
|
||||
mode = 'C';
|
||||
analogWrite(RGBLED_B, rgb_brightness); // blue status indicator
|
||||
Serial.println("Entering config mode");
|
||||
} else {
|
||||
mode = 'N';
|
||||
analogWrite(RGBLED_B, 0);
|
||||
Serial.println("Leaving config mode");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// normal button
|
||||
if (mode == 'N') {
|
||||
// TODO send key code to destination
|
||||
// Send key code to destination
|
||||
atariKeyclick();
|
||||
SendToN2K(keycode[event.buttonId]);
|
||||
if ((event.pressType == ButtonPressType::SHORT)) {
|
||||
SendToN2K(keycode[event.buttonId]);
|
||||
} else if ((event.pressType == ButtonPressType::MEDIUM)) {
|
||||
SendToN2K(longcode[event.buttonId]);
|
||||
}
|
||||
// Debug:
|
||||
if ((event.buttonId == BUTTON_1)
|
||||
and (event.pressType == ButtonPressType::MEDIUM))
|
||||
{
|
||||
print_n2k_devicelist();
|
||||
}
|
||||
} else {
|
||||
// online config mode
|
||||
switch (event.buttonId) {
|
||||
@@ -777,8 +911,11 @@ void loop() {
|
||||
if (millis() - lastSensor >= 5000) {
|
||||
lastSensor = millis();
|
||||
sht.read();
|
||||
temp = sht.getTemperature();
|
||||
hum = sht.getHumidity();
|
||||
temp = sht.getTemperature(); // °C
|
||||
hum = sht.getHumidity(); // Percent
|
||||
|
||||
// Send environment data to NMEA2000
|
||||
send_sensor_temphum(temp + 273.15, hum);
|
||||
}
|
||||
|
||||
// development heartbeat
|
||||
|
||||
Reference in New Issue
Block a user