diff --git a/.github/workflows/build_native.yml b/.github/workflows/build_native.yml index d4b0c8d58..d9591e72c 100644 --- a/.github/workflows/build_native.yml +++ b/.github/workflows/build_native.yml @@ -53,20 +53,18 @@ jobs: - name: Docker login if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }} - uses: docker/login-action@v3 - continue-on-error: true # FIXME: Failing docker login auth - with: - username: meshtastic - password: ${{ secrets.DOCKER_FIRMWARE_TOKEN }} + run: | + echo ${{ secrets.DOCKER_FIRMWARE_TOKEN }} | docker login -u meshtastic --password-stdin + continue-on-error: true - name: Docker setup if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }} - continue-on-error: true # FIXME: Failing docker login auth + continue-on-error: true uses: docker/setup-buildx-action@v3 - name: Docker build and push tagged versions if: ${{ github.event_name == 'workflow_dispatch' }} - continue-on-error: true # FIXME: Failing docker login auth + continue-on-error: true uses: docker/build-push-action@v6 with: context: . @@ -76,7 +74,7 @@ jobs: - name: Docker build and push if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }} - continue-on-error: true # FIXME: Failing docker login auth + continue-on-error: true uses: docker/build-push-action@v6 with: context: . diff --git a/protobufs b/protobufs index 00c9c9932..4a4e81951 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 00c9c9932ea50c14cdc44d497d2672a0031641ce +Subproject commit 4a4e81951d64821a96a5131e50d2b44e5356372e diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 6ad1a953d..2af85e4f5 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -70,6 +70,78 @@ static unsigned char userprefs_admin_key_1[] = USERPREFS_USE_ADMIN_KEY_1; static unsigned char userprefs_admin_key_2[] = USERPREFS_USE_ADMIN_KEY_2; #endif +#ifdef HELTEC_MESH_NODE_T114 + +uint32_t read8(uint8_t bits, uint8_t dummy, uint8_t cs, uint8_t sck, uint8_t mosi, uint8_t dc, uint8_t rst) +{ + uint32_t ret = 0; + uint8_t SDAPIN = mosi; + pinMode(SDAPIN, INPUT_PULLUP); + digitalWrite(dc, HIGH); + for (int i = 0; i < dummy; i++) { // any dummy clocks + digitalWrite(sck, HIGH); + delay(1); + digitalWrite(sck, LOW); + delay(1); + } + for (int i = 0; i < bits; i++) { // read results + ret <<= 1; + delay(1); + if (digitalRead(SDAPIN)) + ret |= 1; + ; + digitalWrite(sck, HIGH); + delay(1); + digitalWrite(sck, LOW); + } + return ret; +} + +void write9(uint8_t val, uint8_t dc_val, uint8_t cs, uint8_t sck, uint8_t mosi, uint8_t dc, uint8_t rst) +{ + pinMode(mosi, OUTPUT); + digitalWrite(dc, dc_val); + for (int i = 0; i < 8; i++) { // send command + digitalWrite(mosi, (val & 0x80) != 0); + delay(1); + digitalWrite(sck, HIGH); + delay(1); + digitalWrite(sck, LOW); + val <<= 1; + } +} + +uint32_t readwrite8(uint8_t cmd, uint8_t bits, uint8_t dummy, uint8_t cs, uint8_t sck, uint8_t mosi, uint8_t dc, uint8_t rst) +{ + digitalWrite(cs, LOW); + write9(cmd, 0, cs, sck, mosi, dc, rst); + uint32_t ret = read8(bits, dummy, cs, sck, mosi, dc, rst); + digitalWrite(cs, HIGH); + return ret; +} + +uint32_t get_st7789_id(uint8_t cs, uint8_t sck, uint8_t mosi, uint8_t dc, uint8_t rst) +{ + pinMode(cs, OUTPUT); + digitalWrite(cs, HIGH); + pinMode(cs, OUTPUT); + pinMode(sck, OUTPUT); + pinMode(mosi, OUTPUT); + pinMode(dc, OUTPUT); + pinMode(rst, OUTPUT); + digitalWrite(rst, LOW); // Hardware Reset + delay(10); + digitalWrite(rst, HIGH); + delay(10); + + uint32_t ID = 0; + ID = readwrite8(0x04, 24, 1, cs, sck, mosi, dc, rst); + ID = readwrite8(0x04, 24, 1, cs, sck, mosi, dc, rst); // ST7789 needs twice + return ID; +} + +#endif + bool meshtastic_DeviceState_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field) { if (ostream) { @@ -489,6 +561,12 @@ void NodeDB::installDefaultConfig(bool preserveKey = false) #if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \ defined(HX8357_CS) || defined(USE_ST7789) bool hasScreen = true; +#ifdef HELTEC_MESH_NODE_T114 + uint32_t st7789_id = get_st7789_id(ST7789_NSS, ST7789_SCK, ST7789_SDA, ST7789_RS, ST7789_RESET); + if (st7789_id == 0xFFFFFF) { + hasScreen = false; + } +#endif #elif ARCH_PORTDUINO bool hasScreen = false; if (settingsMap[displayPanel]) @@ -774,12 +852,12 @@ void NodeDB::installDefaultDeviceState() #ifdef USERPREFS_CONFIG_OWNER_LONG_NAME snprintf(owner.long_name, sizeof(owner.long_name), USERPREFS_CONFIG_OWNER_LONG_NAME); #else - snprintf(owner.long_name, sizeof(owner.long_name), "Meshtastic %02x%02x", ourMacAddr[4], ourMacAddr[5]); + snprintf(owner.long_name, sizeof(owner.long_name), "Meshtastic %04x", getNodeNum() & 0x0ffff); #endif #ifdef USERPREFS_CONFIG_OWNER_SHORT_NAME snprintf(owner.short_name, sizeof(owner.short_name), USERPREFS_CONFIG_OWNER_SHORT_NAME); #else - snprintf(owner.short_name, sizeof(owner.short_name), "%02x%02x", ourMacAddr[4], ourMacAddr[5]); + snprintf(owner.short_name, sizeof(owner.short_name), "%04x", getNodeNum() & 0x0ffff); #endif snprintf(owner.id, sizeof(owner.id), "!%08x", getNodeNum()); // Default node ID now based on nodenum memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr)); diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index da439c375..2c5213cff 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -220,6 +220,9 @@ typedef enum _meshtastic_HardwareModel { the same frame format. Runs on linux, see https://github.com/Jorropo/routastic */ meshtastic_HardwareModel_ROUTASTIC = 85, + /* Mesh-Tab, esp32 based + https://github.com/valzzu/Mesh-Tab */ + meshtastic_HardwareModel_MESH_TAB = 86, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ @@ -414,6 +417,8 @@ typedef enum _meshtastic_MeshPacket_Priority { meshtastic_MeshPacket_Priority_RESPONSE = 80, /* Higher priority for specific message types (portnums) to distinguish between other reliable packets. */ meshtastic_MeshPacket_Priority_HIGH = 100, + /* Higher priority alert message used for critical alerts which take priority over other reliable packets. */ + meshtastic_MeshPacket_Priority_ALERT = 110, /* Ack/naks are sent with very high priority to ensure that retransmission stops as soon as possible */ meshtastic_MeshPacket_Priority_ACK = 120, diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index 874eef60f..a6102e07d 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -79,7 +79,9 @@ typedef enum _meshtastic_TelemetrySensorType { /* SCD40/SCD41 CO2, humidity, temperature sensor */ meshtastic_TelemetrySensorType_SCD4X = 32, /* ClimateGuard RadSens, radiation, Geiger-Muller Tube */ - meshtastic_TelemetrySensorType_RADSENS = 33 + meshtastic_TelemetrySensorType_RADSENS = 33, + /* High accuracy current and voltage */ + meshtastic_TelemetrySensorType_INA226 = 34 } meshtastic_TelemetrySensorType; /* Struct definitions */ @@ -304,8 +306,8 @@ extern "C" { /* Helper constants for enums */ #define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET -#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_RADSENS -#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_RADSENS+1)) +#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_INA226 +#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_INA226+1)) diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 64f7164c9..2b88702ed 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -93,6 +93,7 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer) ResourceNode *nodeJsonScanNetworks = new ResourceNode("/json/scanNetworks", "GET", &handleScanNetworks); ResourceNode *nodeJsonBlinkLED = new ResourceNode("/json/blink", "POST", &handleBlinkLED); ResourceNode *nodeJsonReport = new ResourceNode("/json/report", "GET", &handleReport); + ResourceNode *nodeJsonNodes = new ResourceNode("/json/nodes", "GET", &handleNodes); ResourceNode *nodeJsonFsBrowseStatic = new ResourceNode("/json/fs/browse/static", "GET", &handleFsBrowseStatic); ResourceNode *nodeJsonDelete = new ResourceNode("/json/fs/delete/static", "DELETE", &handleFsDeleteStatic); @@ -112,6 +113,7 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer) secureServer->registerNode(nodeJsonFsBrowseStatic); secureServer->registerNode(nodeJsonDelete); secureServer->registerNode(nodeJsonReport); + secureServer->registerNode(nodeJsonNodes); // secureServer->registerNode(nodeUpdateFs); // secureServer->registerNode(nodeDeleteFs); secureServer->registerNode(nodeAdmin); @@ -680,6 +682,78 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) delete value; } +void handleNodes(HTTPRequest *req, HTTPResponse *res) +{ + ResourceParameters *params = req->getParams(); + std::string content; + + if (!params->getQueryParameter("content", content)) { + content = "json"; + } + + if (content == "json") { + res->setHeader("Content-Type", "application/json"); + res->setHeader("Access-Control-Allow-Origin", "*"); + res->setHeader("Access-Control-Allow-Methods", "GET"); + } else { + res->setHeader("Content-Type", "text/html"); + res->println("
"); + } + + JSONArray nodesArray; + + uint32_t readIndex = 0; + const meshtastic_NodeInfoLite *tempNodeInfo = nodeDB->readNextMeshNode(readIndex); + while (tempNodeInfo != NULL) { + if (tempNodeInfo->has_user) { + JSONObject node; + + char id[16]; + snprintf(id, sizeof(id), "!%08x", tempNodeInfo->num); + + node["id"] = new JSONValue(id); + node["snr"] = new JSONValue(tempNodeInfo->snr); + node["via_mqtt"] = new JSONValue(BoolToString(tempNodeInfo->via_mqtt)); + node["last_heard"] = new JSONValue((int)tempNodeInfo->last_heard); + node["position"] = new JSONValue(); + + if (nodeDB->hasValidPosition(tempNodeInfo)) { + JSONObject position; + position["latitude"] = new JSONValue((float)tempNodeInfo->position.latitude_i * 1e-7); + position["longitude"] = new JSONValue((float)tempNodeInfo->position.longitude_i * 1e-7); + position["altitude"] = new JSONValue((int)tempNodeInfo->position.altitude); + node["position"] = new JSONValue(position); + } + + JSONObject user; + node["long_name"] = new JSONValue(tempNodeInfo->user.long_name); + node["short_name"] = new JSONValue(tempNodeInfo->user.short_name); + char macStr[18]; + snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X", tempNodeInfo->user.macaddr[0], + tempNodeInfo->user.macaddr[1], tempNodeInfo->user.macaddr[2], tempNodeInfo->user.macaddr[3], + tempNodeInfo->user.macaddr[4], tempNodeInfo->user.macaddr[5]); + node["mac_address"] = new JSONValue(macStr); + node["hw_model"] = new JSONValue(tempNodeInfo->user.hw_model); + + nodesArray.push_back(new JSONValue(node)); + } + tempNodeInfo = nodeDB->readNextMeshNode(readIndex); + } + + // collect data to inner data object + JSONObject jsonObjInner; + jsonObjInner["nodes"] = new JSONValue(nodesArray); + + // create json output structure + JSONObject jsonObjOuter; + jsonObjOuter["data"] = new JSONValue(jsonObjInner); + jsonObjOuter["status"] = new JSONValue("ok"); + // serialize and write it to the stream + JSONValue *value = new JSONValue(jsonObjOuter); + res->print(value->Stringify().c_str()); + delete value; +} + /* This supports the Apple Captive Network Assistant (CNA) Portal */ diff --git a/src/mesh/http/ContentHandler.h b/src/mesh/http/ContentHandler.h index 987e3ffef..2066a6d57 100644 --- a/src/mesh/http/ContentHandler.h +++ b/src/mesh/http/ContentHandler.h @@ -13,6 +13,7 @@ void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res); void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res); void handleBlinkLED(HTTPRequest *req, HTTPResponse *res); void handleReport(HTTPRequest *req, HTTPResponse *res); +void handleNodes(HTTPRequest *req, HTTPResponse *res); void handleUpdateFs(HTTPRequest *req, HTTPResponse *res); void handleDeleteFsContent(HTTPRequest *req, HTTPResponse *res); void handleFs(HTTPRequest *req, HTTPResponse *res); diff --git a/src/modules/StoreForwardModule.cpp b/src/modules/StoreForwardModule.cpp index 4cf06f5d2..0a6e1b4c4 100644 --- a/src/modules/StoreForwardModule.cpp +++ b/src/modules/StoreForwardModule.cpp @@ -73,11 +73,11 @@ void StoreForwardModule::populatePSRAM() LOG_DEBUG("Before PSRAM init: heap %d/%d PSRAM %d/%d", memGet.getFreeHeap(), memGet.getHeapSize(), memGet.getFreePsram(), memGet.getPsramSize()); - /* Use a maximum of 2/3 the available PSRAM unless otherwise specified. + /* Use a maximum of 3/4 the available PSRAM unless otherwise specified. Note: This needs to be done after every thing that would use PSRAM */ uint32_t numberOfPackets = - (this->records ? this->records : (((memGet.getFreePsram() / 3) * 2) / sizeof(PacketHistoryStruct))); + (this->records ? this->records : (((memGet.getFreePsram() / 4) * 3) / sizeof(PacketHistoryStruct))); this->records = numberOfPackets; #if defined(ARCH_ESP32) this->packetHistory = static_cast(ps_calloc(numberOfPackets, sizeof(PacketHistoryStruct))); @@ -198,6 +198,9 @@ void StoreForwardModule::historyAdd(const meshtastic_MeshPacket &mp) this->packetHistory[this->packetHistoryTotalCount].to = mp.to; this->packetHistory[this->packetHistoryTotalCount].channel = mp.channel; this->packetHistory[this->packetHistoryTotalCount].from = getFrom(&mp); + this->packetHistory[this->packetHistoryTotalCount].id = mp.id; + this->packetHistory[this->packetHistoryTotalCount].reply_id = p.reply_id; + this->packetHistory[this->packetHistoryTotalCount].emoji = (bool)p.emoji; this->packetHistory[this->packetHistoryTotalCount].payload_size = p.payload.size; memcpy(this->packetHistory[this->packetHistoryTotalCount].payload, p.payload.bytes, meshtastic_Constants_DATA_PAYLOAD_LEN); @@ -244,8 +247,11 @@ meshtastic_MeshPacket *StoreForwardModule::preparePayload(NodeNum dest, uint32_t p->to = local ? this->packetHistory[i].to : dest; // PhoneAPI can handle original `to` p->from = this->packetHistory[i].from; + p->id = this->packetHistory[i].id; p->channel = this->packetHistory[i].channel; + p->decoded.reply_id = this->packetHistory[i].reply_id; p->rx_time = this->packetHistory[i].time; + p->decoded.emoji = (uint32_t)this->packetHistory[i].emoji; // Let's assume that if the server received the S&F request that the client is in range. // TODO: Make this configurable. @@ -617,4 +623,4 @@ StoreForwardModule::StoreForwardModule() disable(); } #endif -} +} \ No newline at end of file diff --git a/src/modules/StoreForwardModule.h b/src/modules/StoreForwardModule.h index e3273470b..30db1625c 100644 --- a/src/modules/StoreForwardModule.h +++ b/src/modules/StoreForwardModule.h @@ -13,7 +13,10 @@ struct PacketHistoryStruct { uint32_t time; uint32_t to; uint32_t from; + uint32_t id; uint8_t channel; + uint32_t reply_id; + bool emoji; uint8_t payload[meshtastic_Constants_DATA_PAYLOAD_LEN]; pb_size_t payload_size; }; diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp index 362d60252..6a8077f03 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.cpp +++ b/src/modules/Telemetry/AirQualityTelemetry.cpp @@ -113,12 +113,18 @@ bool AirQualityTelemetryModule::getAirQualityTelemetry(meshtastic_Telemetry *m) m->time = getTime(); m->which_variant = meshtastic_Telemetry_air_quality_metrics_tag; + m->variant.air_quality_metrics.has_pm10_standard = true; m->variant.air_quality_metrics.pm10_standard = data.pm10_standard; + m->variant.air_quality_metrics.has_pm25_standard = true; m->variant.air_quality_metrics.pm25_standard = data.pm25_standard; + m->variant.air_quality_metrics.has_pm100_standard = true; m->variant.air_quality_metrics.pm100_standard = data.pm100_standard; + m->variant.air_quality_metrics.has_pm10_environmental = true; m->variant.air_quality_metrics.pm10_environmental = data.pm10_env; + m->variant.air_quality_metrics.has_pm25_environmental = true; m->variant.air_quality_metrics.pm25_environmental = data.pm25_env; + m->variant.air_quality_metrics.has_pm100_environmental = true; m->variant.air_quality_metrics.pm100_environmental = data.pm100_env; LOG_INFO("Send: PM1.0(Standard)=%i, PM2.5(Standard)=%i, PM10.0(Standard)=%i", m->variant.air_quality_metrics.pm10_standard, diff --git a/variants/portduino-buildroot/platformio.ini b/variants/portduino-buildroot/platformio.ini index 3c8f21537..683a3cecc 100644 --- a/variants/portduino-buildroot/platformio.ini +++ b/variants/portduino-buildroot/platformio.ini @@ -1,11 +1,9 @@ [env:buildroot] extends = portduino_base -; The pkg-config commands below optionally add link flags. -; the || : is just a "or run the null command" to avoid returning an error code +; Optional libraries should be appended to `PLATFORMIO_BUILD_FLAGS` +; environment variable in the buildroot environment. build_flags = ${portduino_base.build_flags} -O0 -I variants/portduino-buildroot -std=c++17 - !pkg-config --libs libulfius --silence-errors || : - !pkg-config --libs openssl --silence-errors || : board = buildroot lib_deps = ${portduino_base.lib_deps} build_src_filter = ${portduino_base.build_src_filter} diff --git a/variants/rp2040-lora/variant.h b/variants/rp2040-lora/variant.h index f1826605f..92b067457 100644 --- a/variants/rp2040-lora/variant.h +++ b/variants/rp2040-lora/variant.h @@ -15,7 +15,7 @@ // rxd = 9 #define EXT_NOTIFY_OUT 22 -#undef BUTTON_PIN // Pin 17 used for antenna switching via DIO4 +#define BUTTON_PIN -1 // Pin 17 used for antenna switching via DIO4 #define LED_PIN PIN_LED @@ -57,4 +57,4 @@ #define SX126X_DIO2_AS_RF_SWITCH // Antenna switch CTRL #define SX126X_RXEN LORA_DIO4 // Antenna switch !CTRL via GPIO17 // #define SX126X_DIO3_TCXO_VOLTAGE 1.8 -#endif \ No newline at end of file +#endif