• TNC mode allows an RNode to be used as a KISS compatible TNC over the Serial Port.
• This mode makes it usable with amateur radio software that can talk to a KISS TNC over a serial port.
• You must leave TNC mode disabled when using RNode with apps like MeshChat or Sideband.
-
-
+
Configure Display (optional)
-
-
Rotation
-
+
+
Intensity
+
+
+
+ Set Display Intensity
+
+
+
+
+
+
Timeout (sec)
+
+
+
+ Set Display Timeout
+
+
+
+
-
Reconditioning
-
+ Reconditioning
+
Start
-
+
Stop
+
+
+
+
+
+ Configure WiFi (optional)
-
-
Setting display rotation requires firmware v1.80+
+
+
• WiFi configuration is supported only on ESP32 devices.
+
• Simultaneous operation of Bluetooth and WiFi is unsupported.
+
• For static IP configuration both the address and the netmask need to be set.
+
• Unset both IP and Netmask to use DHCP.
+
+
+
+
Channel
+
+
+
+ Set Channel
+
+
+
+
+
+
SSID
+
+
+
+ Set SSID
+
+
+ Unset SSID
+
+
+
+
+
+
PSK (Password)
+
+
+
+
+
+
+ Set PSK
+
+
+
+ Password must be at least 8 characters.
+
+
+
+ Unset PSK
+
+
+
+
+
+
IP Address
+
+
+
+ Set IP
+
+
+ Unset IP
+
+
+
+
+
+
Netmask
+
+
+
+ Set Netmask
+
+
+ Unset Netmask
+
+
+
@@ -390,78 +505,63 @@
selectedModel: null,
products: [
{
- name: "Heltec LoRa32 v2",
- id: ROM.PRODUCT_H32_V2,
+ name: "Aethernode",
+ id: ROM.PRODUCT_HMBRW,
platform: ROM.PLATFORM_ESP32,
models: [
{
- id: ROM.MODEL_C4,
+ id: ROM.MODEL_FE,
name: "433 MHz",
},
- {
- id: ROM.MODEL_C9,
- name: "868 MHz / 915 MHz / 923 MHz",
- },
],
- firmware_filename: "rnode_firmware_heltec32v2.zip",
+ firmware_filename: "rnode_firmware_aethernode.zip",
+ firmware_repo: "https://github.com/ahedproductions/aethernode",
flash_config: {
- flash_size: "8MB",
+ flash_size: "4MB",
flash_files: {
- "0xe000": "rnode_firmware_heltec32v2.boot_app0",
- "0x1000": "rnode_firmware_heltec32v2.bootloader",
- "0x10000": "rnode_firmware_heltec32v2.bin",
+ "0xe000": "rnode_firmware_aethernode.boot_app0",
+ "0x1000": "rnode_firmware_aethernode.bootloader",
+ "0x10000": "rnode_firmware_aethernode.bin",
"0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_heltec32v2.partitions",
+ "0x8000": "rnode_firmware_aethernode.partitions",
},
},
},
{
- name: "Heltec LoRa32 v3",
- id: ROM.PRODUCT_H32_V3,
+ name: "MeshAdventurer",
+ id: ROM.PRODUCT_HMBRW,
platform: ROM.PLATFORM_ESP32,
models: [
{
- id: ROM.MODEL_C5,
- name: "433 MHz",
- },
- {
- id: ROM.MODEL_CA,
- name: "868 MHz / 915 MHz / 923 MHz",
+ id: ROM.MODEL_FE,
+ name: "868 MHz",
},
],
- firmware_filename: "rnode_firmware_heltec32v3.zip",
+ firmware_filename: "rnode_firmware_meshadventurer.zip",
+ firmware_repo: "https://github.com/chrismyers2000/MeshAdventurer",
flash_config: {
- flash_size: "8MB",
+ flash_size: "4MB",
flash_files: {
- "0xe000": "rnode_firmware_heltec32v3.boot_app0",
- "0x0": "rnode_firmware_heltec32v3.bootloader",
- "0x10000": "rnode_firmware_heltec32v3.bin",
+ "0xe000": "rnode_firmware_meshadventurer.boot_app0",
+ "0x1000": "rnode_firmware_meshadventurer.bootloader",
+ "0x10000": "rnode_firmware_meshadventurer.bin",
"0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_heltec32v3.partitions",
+ "0x8000": "rnode_firmware_meshadventurer.partitions",
},
},
},
{
- name: "Heltec LoRa32 v4",
- id: ROM.PRODUCT_H32_V4,
- platform: ROM.PLATFORM_ESP32,
+ name: "FakeTec (Promicro)",
+ id: ROM.PRODUCT_HMBRW,
+ platform: ROM.PLATFORM_NRF52,
models: [
{
- id: ROM.MODEL_C8,
- name: "868 MHz / 915 MHz / 923 MHz with PA",
+ id: ROM.MODEL_FE,
+ name: "863-928 MHz",
},
],
- firmware_filename: "rnode_firmware_heltec32v4pa.zip",
- flash_config: {
- flash_size: "16MB",
- flash_files: {
- "0xe000": "rnode_firmware_heltec32v4pa.boot_app0",
- "0x0": "rnode_firmware_heltec32v4pa.bootloader",
- "0x10000": "rnode_firmware_heltec32v4pa.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_heltec32v4pa.partitions",
- },
- },
+ firmware_filename: "rnode_firmware_promicro.zip",
+ firmware_repo: "https://github.com/gargomoma/fakeTec_pcb",
},
{
name: "Heltec T114",
@@ -478,440 +578,24 @@
},
],
firmware_filename: "rnode_firmware_heltec_t114.zip",
- },
- {
- name: "LilyGO LoRa32 v1.0",
- id: ROM.PRODUCT_T32_10,
- platform: ROM.PLATFORM_ESP32,
- models: [
- {
- id: ROM.MODEL_BA,
- name: "433 MHz",
- },
- {
- id: ROM.MODEL_BB,
- name: "868 MHz / 915 MHz / 923 MHz",
- },
- ],
- firmware_filename: "rnode_firmware_lora32v10.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_lora32v10.boot_app0",
- "0x1000": "rnode_firmware_lora32v10.bootloader",
- "0x10000": "rnode_firmware_lora32v10.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_lora32v10.partitions",
- },
- },
- },
- {
- name: "LilyGO LoRa32 v2.0",
- id: ROM.PRODUCT_T32_20,
- platform: ROM.PLATFORM_ESP32,
- models: [
- {
- id: ROM.MODEL_B3,
- name: "433 MHz",
- },
- {
- id: ROM.MODEL_B8,
- name: "868 MHz / 915 MHz / 923 MHz",
- },
- ],
- firmware_filename: "rnode_firmware_lora32v20.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_lora32v20.boot_app0",
- "0x1000": "rnode_firmware_lora32v20.bootloader",
- "0x10000": "rnode_firmware_lora32v20.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_lora32v20.partitions",
- },
- },
- },
- {
- name: "LilyGO LoRa32 v2.1",
- id: ROM.PRODUCT_T32_21,
- platform: ROM.PLATFORM_ESP32,
- models: [
- {
- id: ROM.MODEL_B4,
- name: "433 MHz",
- firmware_filename: "rnode_firmware_lora32v21.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_lora32v21.boot_app0",
- "0x1000": "rnode_firmware_lora32v21.bootloader",
- "0x10000": "rnode_firmware_lora32v21.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_lora32v21.partitions",
- },
- },
- },
- {
- id: ROM.MODEL_B9,
- name: "868/915/923 MHz",
- firmware_filename: "rnode_firmware_lora32v21.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_lora32v21.boot_app0",
- "0x1000": "rnode_firmware_lora32v21.bootloader",
- "0x10000": "rnode_firmware_lora32v21.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_lora32v21.partitions",
- },
- },
- },
- // The TCXO model codes are only used here to select the correct firmware,
- // actual model codes in firmware is still 0xB4 and 0xB9.
- // https://github.com/markqvist/Reticulum/blob/master/RNS/Utilities/rnodeconf.py#L156
- // https://github.com/markqvist/Reticulum/blob/master/RNS/Utilities/rnodeconf.py#L3283
- {
- id: ROM.MODEL_B4_TCXO,
- mapped_id: ROM.MODEL_B4, // this device uses the same model code, but different firmware file
- name: "433 MHz, with TCXO",
- firmware_filename: "rnode_firmware_lora32v21_tcxo.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_lora32v21_tcxo.boot_app0",
- "0x1000": "rnode_firmware_lora32v21_tcxo.bootloader",
- "0x10000": "rnode_firmware_lora32v21_tcxo.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_lora32v21_tcxo.partitions",
- },
- },
- },
- {
- id: ROM.MODEL_B9_TCXO,
- mapped_id: ROM.MODEL_B9, // this device uses the same model code, but different firmware file
- name: "868/915/923 MHz, with TCXO",
- firmware_filename: "rnode_firmware_lora32v21_tcxo.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_lora32v21_tcxo.boot_app0",
- "0x1000": "rnode_firmware_lora32v21_tcxo.bootloader",
- "0x10000": "rnode_firmware_lora32v21_tcxo.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_lora32v21_tcxo.partitions",
- },
- },
- },
- ],
- },
- {
- name: "LilyGO LoRa T3S3",
- id: ROM.PRODUCT_RNODE,
- platform: ROM.PLATFORM_ESP32,
- models: [
- {
- id: ROM.MODEL_A5,
- name: "433 MHz (with SX1278 chip)",
- firmware_filename: "rnode_firmware_t3s3_sx127x.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_t3s3_sx127x.boot_app0",
- "0x0": "rnode_firmware_t3s3_sx127x.bootloader",
- "0x10000": "rnode_firmware_t3s3_sx127x.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_t3s3_sx127x.partitions",
- },
- },
- },
- {
- id: ROM.MODEL_AA,
- name: "868/915/923 MHz (with SX1276 chip)",
- firmware_filename: "rnode_firmware_t3s3_sx127x.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_t3s3_sx127x.boot_app0",
- "0x0": "rnode_firmware_t3s3_sx127x.bootloader",
- "0x10000": "rnode_firmware_t3s3_sx127x.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_t3s3_sx127x.partitions",
- },
- },
- },
- {
- id: ROM.MODEL_A1,
- name: "433 MHz (with SX1268 chip)",
- firmware_filename: "rnode_firmware_t3s3.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_t3s3.boot_app0",
- "0x0": "rnode_firmware_t3s3.bootloader",
- "0x10000": "rnode_firmware_t3s3.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_t3s3.partitions",
- },
- },
- },
- {
- id: ROM.MODEL_A6,
- name: "868/915/923 MHz (with SX1262 chip)",
- firmware_filename: "rnode_firmware_t3s3.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_t3s3.boot_app0",
- "0x0": "rnode_firmware_t3s3.bootloader",
- "0x10000": "rnode_firmware_t3s3.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_t3s3.partitions",
- },
- },
- },
- {
- id: ROM.MODEL_AC,
- name: "2.4 GHz (with SX1280 chip)",
- firmware_filename: "rnode_firmware_t3s3_sx1280_pa.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_t3s3_sx1280_pa.boot_app0",
- "0x0": "rnode_firmware_t3s3_sx1280_pa.bootloader",
- "0x10000": "rnode_firmware_t3s3_sx1280_pa.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_t3s3_sx1280_pa.partitions",
- },
- },
- },
- ],
- },
- {
- name: "LilyGO T-Beam",
- id: ROM.PRODUCT_TBEAM,
- platform: ROM.PLATFORM_ESP32,
- models: [
- {
- id: ROM.MODEL_E4,
- name: "433 MHz (with SX1278 chip)",
- firmware_filename: "rnode_firmware_tbeam.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_tbeam.boot_app0",
- "0x1000": "rnode_firmware_tbeam.bootloader",
- "0x10000": "rnode_firmware_tbeam.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_tbeam.partitions",
- },
- },
- },
- {
- id: ROM.MODEL_E9,
- name: "868/915/923 MHz (with SX1276 chip)",
- firmware_filename: "rnode_firmware_tbeam.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_tbeam.boot_app0",
- "0x1000": "rnode_firmware_tbeam.bootloader",
- "0x10000": "rnode_firmware_tbeam.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_tbeam.partitions",
- },
- },
- },
- {
- id: ROM.MODEL_E3,
- name: "433 MHz (with SX1268 chip)",
- firmware_filename: "rnode_firmware_tbeam_sx1262.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_tbeam_sx1262.boot_app0",
- "0x1000": "rnode_firmware_tbeam_sx1262.bootloader",
- "0x10000": "rnode_firmware_tbeam_sx1262.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_tbeam_sx1262.partitions",
- },
- },
- },
- {
- id: ROM.MODEL_E8,
- name: "868/915/923 MHz (with SX1262 chip)",
- firmware_filename: "rnode_firmware_tbeam_sx1262.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_tbeam_sx1262.boot_app0",
- "0x1000": "rnode_firmware_tbeam_sx1262.bootloader",
- "0x10000": "rnode_firmware_tbeam_sx1262.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_tbeam_sx1262.partitions",
- },
- },
- },
- ],
- },
- {
- name: "LilyGO T-Beam Supreme",
- id: ROM.PRODUCT_TBEAM_S_V1,
- platform: ROM.PLATFORM_ESP32,
- models: [
- {
- id: ROM.MODEL_DB,
- name: "433 MHz (with SX1268 chip)",
- },
- {
- id: ROM.MODEL_DC,
- name: "868/915/923 MHz (with SX1262 chip)",
- },
- ],
- firmware_filename: "rnode_firmware_tbeam_supreme.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_tbeam_supreme.boot_app0",
- "0x0": "rnode_firmware_tbeam_supreme.bootloader",
- "0x10000": "rnode_firmware_tbeam_supreme.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_tbeam_supreme.partitions",
- },
- },
- },
- {
- name: "LilyGO T-Deck",
- id: ROM.PRODUCT_TDECK,
- platform: ROM.PLATFORM_ESP32,
- models: [
- {
- id: ROM.MODEL_D4,
- name: "433 MHz (with SX1268 chip)",
- },
- {
- id: ROM.MODEL_D9,
- name: "868/915/923 MHz (with SX1262 chip)",
- },
- ],
- firmware_filename: "rnode_firmware_tdeck.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_tdeck.boot_app0",
- "0x0": "rnode_firmware_tdeck.bootloader",
- "0x10000": "rnode_firmware_tdeck.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_tdeck.partitions",
- },
- },
- },
- {
- name: "LilyGO T-Echo",
- id: ROM.PRODUCT_TECHO,
- platform: ROM.PLATFORM_NRF52,
- models: [
- {
- id: ROM.MODEL_16,
- name: "433 MHz",
- },
- {
- id: ROM.MODEL_17,
- name: "868 MHz / 915 MHz / 923 MHz",
- },
- ],
- firmware_filename: "rnode_firmware_techo.zip",
- },
- {
- name: "RAK4631",
- id: ROM.PRODUCT_RAK4631,
- platform: ROM.PLATFORM_NRF52,
- models: [
- {
- id: ROM.MODEL_11,
- name: "433 MHz",
- },
- {
- id: ROM.MODEL_12,
- name: "868 MHz / 915 MHz / 923 MHz",
- },
- ],
- firmware_filename: "rnode_firmware_rak4631.zip",
- },
- {
- name: "RNode",
- id: ROM.PRODUCT_RNODE,
- platform: ROM.PLATFORM_ESP32,
- models: [
- {
- id: ROM.MODEL_A2,
- name: "Handheld v2.1 RNode, 410 - 525 MHz",
- firmware_filename: "rnode_firmware_ng21.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_ng21.boot_app0",
- "0x1000": "rnode_firmware_ng21.bootloader",
- "0x10000": "rnode_firmware_ng21.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_ng21.partitions",
- },
- },
- },
- {
- id: ROM.MODEL_A7,
- name: "Handheld v2.1 RNode, 820 - 1020 MHz",
- firmware_filename: "rnode_firmware_ng21.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_ng21.boot_app0",
- "0x1000": "rnode_firmware_ng21.bootloader",
- "0x10000": "rnode_firmware_ng21.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_ng21.partitions",
- },
- },
- },
- {
- id: ROM.MODEL_A1,
- name: "Prototype v2.2 RNode, 410 - 525 MHz",
- firmware_filename: "rnode_firmware_t3s3.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_t3s3.boot_app0",
- "0x0": "rnode_firmware_t3s3.bootloader",
- "0x10000": "rnode_firmware_t3s3.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_t3s3.partitions",
- },
- },
- },
- {
- id: ROM.MODEL_A6,
- name: "Prototype v2.2 RNode, 820 - 1020 MHz",
- firmware_filename: "rnode_firmware_t3s3.zip",
- flash_config: {
- flash_size: "4MB",
- flash_files: {
- "0xe000": "rnode_firmware_t3s3.boot_app0",
- "0x0": "rnode_firmware_t3s3.bootloader",
- "0x10000": "rnode_firmware_t3s3.bin",
- "0x210000": "console_image.bin",
- "0x8000": "rnode_firmware_t3s3.partitions",
- },
- },
- },
- ],
+ firmware_repo: "https://heltec.org/project/mesh-node-t114/",
},
],
- // Liam's default config for New Zealand / LongFast on Slot 10
- configFrequency: 917375000,
+ // Default config
+ configFrequency: 433175000,
configBandwidth: 250000,
configTxPower: 22,
configSpreadingFactor: 11,
configCodingRate: 5,
+ displayIntensity: 255,
+ displayTimeout: 0,
+ wifiMode: null,
+ wifiChannel: 1,
+ wifiSSID: "",
+ wifiPSK: "",
+ wifiIP: "",
+ wifiNM: "",
RNodeInterfaceDefaults: {
bandwidths: [ // bandwidth in hz
@@ -942,10 +626,15 @@
],
},
+ // Flag to track if we're in the initial setup
+ isInitializing: true,
+
};
},
mounted() {
-
+ // Set default selections after component is mounted
+ this.selectedProduct = this.products[0];
+ this.selectedModel = this.products[0].models[0];
},
methods: {
async askForSerialPort() {
@@ -1060,7 +749,7 @@
// close port
console.log("Closing serial port");
try {
- await this.serialPort.close();
+ await serialPort.close();
} catch(e) {
console.log("failed to close serial port, ignoring...", e);
}
@@ -1219,6 +908,7 @@
rx_stat: await rnode.getRxStat(),
tx_stat: await rnode.getTxStat(),
rssi_stat: await rnode.getRssiStat(),
+ wifi_mode: await rnode.getWifiMode(),
});
await rnode.close();
@@ -1787,6 +1477,331 @@
"- Bluetooth pin will shown on your RNode screen and on this page.",
].join("\n"));
+ },
+
+ async setWiFiMode() {
+
+ // ask for rnode
+ const rnode = await this.askForRNode();
+ if (!rnode) {
+ return;
+ }
+
+ // check if device has been provisioned
+ const rom = await rnode.getRomAsObject();
+ const details = rom.parse();
+ if (!details || !details.is_provisioned) {
+ alert("Eeprom is not provisioned. You must do this first!");
+ await rnode.close();
+ return;
+ }
+
+ // normalize mode to number (safety)
+ const mode = Number(this.wifiMode);
+
+ console.log("setting wifi mode to", mode);
+
+ await rnode.enableWiFiMode(mode);
+
+ console.log("setting wifi mode: done");
+
+ const modeMap = {
+ 0: "OFF",
+ 1: "STATION",
+ 2: "AP"
+ };
+
+ const modeLabel = modeMap[mode] ?? "UNKNOWN";
+
+ alert("WiFi mode has been set to " + modeLabel + "!");
+
+ // update UI if needed
+ this.wifiMode = mode;
+
+ // done
+ await Utils.sleepMillis(1000);
+ await rnode.close();
+ },
+
+ async setWiFiChannel() {
+
+ // ask for rnode
+ const rnode = await this.askForRNode();
+ if(!rnode){
+ return;
+ }
+
+ // check if device has been provisioned
+ const rom = await rnode.getRomAsObject();
+ const details = rom.parse();
+ if(!details || !details.is_provisioned){
+ alert("Eeprom is not provisioned. You must do this first!");
+ await rnode.close();
+ return;
+ }
+
+ // set wifi channel
+ console.log("setting wifi channel to", this.wifiChannel);
+ await rnode.setWiFiChannel(this.wifiChannel);
+ console.log("setting wifi channel: done");
+ alert("WiFi channel has been set to " + this.wifiChannel + "!");
+
+ // done
+ await Utils.sleepMillis(1000);
+ await rnode.close();
+ },
+ async setWiFiSSID() {
+
+ // ask for rnode
+ const rnode = await this.askForRNode();
+ if(!rnode){
+ return;
+ }
+
+ // check if device has been provisioned
+ const rom = await rnode.getRomAsObject();
+ const details = rom.parse();
+ if(!details || !details.is_provisioned){
+ alert("Eeprom is not provisioned. You must do this first!");
+ await rnode.close();
+ return;
+ }
+
+ // set wifi SSID
+ console.log("setting wifi SSID to", this.wifiSSID);
+ await rnode.setWiFiSSID(this.wifiSSID);
+ console.log("setting wifi SSID: done");
+ alert("WiFi SSID has been set to " + this.wifiSSID + "!");
+
+ // done
+ await Utils.sleepMillis(1000);
+ await rnode.close();
+
+ },
+ async disableWiFiMode() {
+
+ // ask for rnode
+ const rnode = await this.askForRNode();
+ if(!rnode){
+ return;
+ }
+
+ // check if device has been provisioned
+ const rom = await rnode.getRomAsObject();
+ const details = rom.parse();
+ if(!details || !details.is_provisioned){
+ alert("Eeprom is not provisioned. You must do this first!");
+ await rnode.close();
+ return;
+ }
+
+ // disable wifi mode
+ console.log("disabling wifi mode");
+ await rnode.disableWiFiMode();
+ console.log("disabling wifi mode: done");
+ alert("WiFi mode has been disabled!");
+
+ // done
+ await Utils.sleepMillis(1000);
+ await rnode.close();
+
+ },
+ async setWiFiPSK() {
+
+ // ask for rnode
+ const rnode = await this.askForRNode();
+ if(!rnode){
+ return;
+ }
+
+ // check if device has been provisioned
+ const rom = await rnode.getRomAsObject();
+ const details = rom.parse();
+ if(!details || !details.is_provisioned){
+ alert("Eeprom is not provisioned. You must do this first!");
+ await rnode.close();
+ return;
+ }
+
+ // set wifi psk
+ console.log("setting wifi psk to", this.wifiPSK);
+ await rnode.setWiFiPSK(this.wifiPSK);
+ console.log("setting wifi psk: done");
+ alert("WiFi PSK has been set!");
+
+ // done
+ await Utils.sleepMillis(1000);
+ await rnode.close();
+
+ },
+ async unsetWiFiSSID() {
+
+ // ask for rnode
+ const rnode = await this.askForRNode();
+ if(!rnode){
+ return;
+ }
+
+ // check if device has been provisioned
+ const rom = await rnode.getRomAsObject();
+ const details = rom.parse();
+ if(!details || !details.is_provisioned){
+ alert("Eeprom is not provisioned. You must do this first!");
+ await rnode.close();
+ return;
+ }
+
+ // unset wifi SSID by setting it to "None"
+ console.log("unsetting wifi SSID");
+ await rnode.setWiFiSSID("None");
+ console.log("unsetting wifi SSID: done");
+ alert("WiFi SSID has been unset!");
+
+ // update UI
+ this.wifiSSID = "None";
+
+ // done
+ await Utils.sleepMillis(1000);
+ await rnode.close();
+
+ },
+ async unsetWiFiPSK() {
+
+ // ask for rnode
+ const rnode = await this.askForRNode();
+ if(!rnode){
+ return;
+ }
+
+ // check if device has been provisioned
+ const rom = await rnode.getRomAsObject();
+ const details = rom.parse();
+ if(!details || !details.is_provisioned){
+ alert("Eeprom is not provisioned. You must do this first!");
+ await rnode.close();
+ return;
+ }
+
+ // unset wifi psk by setting it to "None"
+ console.log("unsetting wifi psk");
+ await rnode.setWiFiPSK(null);
+ console.log("unsetting wifi psk: done");
+ alert("WiFi PSK has been unset!");
+
+ // update UI
+ this.wifiPSK = "";
+
+ // done
+ await Utils.sleepMillis(1000);
+ await rnode.close();
+
+ },
+
+ async unsetWiFiIP() {
+
+ const rnode = await this.askForRNode();
+ if (!rnode) return;
+
+ const rom = await rnode.getRomAsObject();
+ const details = rom.parse();
+ if (!details || !details.is_provisioned) {
+ alert("Eeprom is not provisioned. You must do this first!");
+ await rnode.close();
+ return;
+ }
+
+ console.log("unsetting wifi ip");
+
+ await rnode.setWiFiIP(null);
+
+ console.log("unsetting wifi ip: done");
+
+ this.wifiIP = "";
+
+ await Utils.sleepMillis(1000);
+ await rnode.close();
+ },
+
+ async unsetWiFiNM() {
+
+ const rnode = await this.askForRNode();
+ if (!rnode) return;
+
+ const rom = await rnode.getRomAsObject();
+ const details = rom.parse();
+ if (!details || !details.is_provisioned) {
+ alert("Eeprom is not provisioned. You must do this first!");
+ await rnode.close();
+ return;
+ }
+
+ console.log("unsetting wifi netmask");
+
+ await rnode.setWiFiNM(null);
+
+ console.log("unsetting wifi netmask: done");
+
+ this.wifiNM = "";
+
+ await Utils.sleepMillis(1000);
+ await rnode.close();
+ },
+
+ async setWiFiIP() {
+
+ // ask for rnode
+ const rnode = await this.askForRNode();
+ if(!rnode){
+ return;
+ }
+
+ // check if device has been provisioned
+ const rom = await rnode.getRomAsObject();
+ const details = rom.parse();
+ if(!details || !details.is_provisioned){
+ alert("Eeprom is not provisioned. You must do this first!");
+ await rnode.close();
+ return;
+ }
+
+ // set wifi ip
+ console.log("setting wifi ip to", this.wifiIP);
+ await rnode.setWiFiIP(this.wifiIP);
+ console.log("setting wifi ip: done");
+ alert("WiFi IP has been set to " + this.wifiIP + "!");
+
+ // done
+ await Utils.sleepMillis(1000);
+ await rnode.close();
+
+ },
+ async setWiFiNM() {
+
+ // ask for rnode
+ const rnode = await this.askForRNode();
+ if(!rnode){
+ return;
+ }
+
+ // check if device has been provisioned
+ const rom = await rnode.getRomAsObject();
+ const details = rom.parse();
+ if(!details || !details.is_provisioned){
+ alert("Eeprom is not provisioned. You must do this first!");
+ await rnode.close();
+ return;
+ }
+
+ // set wifi nm
+ console.log("setting wifi nm to", this.wifiNM);
+ await rnode.setWiFiNM(this.wifiNM);
+ console.log("setting wifi nm: done");
+ alert("WiFi Netmask has been set to " + this.wifiNM + "!");
+
+ // done
+ await Utils.sleepMillis(1000);
+ await rnode.close();
+
},
async setDisplayRotation(rotation) {
@@ -1813,6 +1828,58 @@
// done
await rnode.close();
+ },
+ async setDisplayIntensity(intensity) {
+
+ // ask for rnode
+ const rnode = await this.askForRNode();
+ if(!rnode){
+ return;
+ }
+
+ // check if device has been provisioned
+ const rom = await rnode.getRomAsObject();
+ const details = rom.parse();
+ if(!details || !details.is_provisioned){
+ alert("Eeprom is not provisioned. You must do this first!");
+ await rnode.close();
+ return;
+ }
+
+ // configure
+ console.log("setting display intensity");
+ await rnode.setDisplayIntensity(intensity);
+ console.log("setting display intensity: done");
+
+ // done
+ await rnode.close();
+
+ },
+ async setDisplayTimeout(timeout) {
+
+ // ask for rnode
+ const rnode = await this.askForRNode();
+ if(!rnode){
+ return;
+ }
+
+ // check if device has been provisioned
+ const rom = await rnode.getRomAsObject();
+ const details = rom.parse();
+ if(!details || !details.is_provisioned){
+ alert("Eeprom is not provisioned. You must do this first!");
+ await rnode.close();
+ return;
+ }
+
+ // configure
+ console.log("setting display timeout");
+ await rnode.setDisplayTimeout(timeout);
+ console.log("setting display timeout: done");
+
+ // done
+ await rnode.close();
+
},
async startDisplayReconditioning() {
@@ -1854,11 +1921,63 @@
recommendedFirmwareFilename() {
return this.selectedModel?.firmware_filename ?? this.selectedProduct?.firmware_filename;
},
+ FirmwareRepo() {
+ return this.selectedModel?.firmware_repo ?? this.selectedProduct?.firmware_repo;
+ },
+ isSsidValid() {
+ if (!this.wifiSSID) return false;
+
+ const encoder = new TextEncoder();
+ const bytes = encoder.encode(this.wifiSSID);
+
+ return bytes.length >= 1 && bytes.length <= 32;
+ },
+ isPskValid() {
+ if (!this.wifiPSK) return false;
+
+ const encoder = new TextEncoder();
+ const bytes = encoder.encode(this.wifiPSK);
+
+ return bytes.length >= 8;
+ },
+ isIpValid() {
+ if (!this.wifiIP) return false;
+
+ const parts = this.wifiIP.split(".");
+ if (parts.length !== 4) return false;
+
+ for (const part of parts) {
+ if (part === "") return false;
+
+ const num = Number(part);
+ if (!Number.isInteger(num)) return false;
+ if (num < 0 || num > 255) return false;
+ }
+ return true;
+ },
+ isNetmaskValid() {
+ if (!this.wifiNM) return false;
+
+ const parts = this.wifiNM.split(".");
+ if (parts.length !== 4) return false;
+
+ for (const part of parts) {
+ if (part === "") return false;
+
+ const num = Number(part);
+ if (!Number.isInteger(num)) return false;
+ if (num < 0 || num > 255) return false;
+ }
+
+ return true;
+ },
},
watch: {
selectedProduct() {
- // reset selected model when changing selected product
- this.selectedModel = null;
+ // reset selected model when changing selected product, but not during initialization
+ if (!this.isInitializing) {
+ this.selectedModel = null;
+ }
},
},
}).mount('#app');
diff --git a/js/rnode.js b/js/rnode.js
index 120ca40..f49c9df 100644
--- a/js/rnode.js
+++ b/js/rnode.js
@@ -80,7 +80,15 @@ class RNode {
CMD_HASHES = 0x60;
CMD_FW_UPD = 0x61;
CMD_DISP_ROT = 0x67;
+ CMD_DISP_INT = 0x45;
+ CMD_DISP_BLNK = 0x64;
CMD_DISP_RCND = 0x68;
+ CMD_WIFI_MODE = 0x6A;
+ CMD_WIFI_SSID = 0x6B;
+ CMD_WIFI_PSK = 0x6C;
+ CMD_WIFI_CHN = 0x6E;
+ CMD_WIFI_IP = 0x84;
+ CMD_WIFI_NM = 0x85;
CMD_BT_CTRL = 0x46;
CMD_BT_PIN = 0x62;
@@ -610,6 +618,185 @@ class RNode {
}
+ async enableWiFiMode(wifiMode) {
+ await this.sendKissCommand([
+ this.CMD_WIFI_MODE,
+ wifiMode, // 0x00 = OFF, 0x01 = AP, 0x02 = STATION
+ ]);
+ }
+
+ async disableWiFiMode() {
+ await this.sendKissCommand([
+ this.CMD_WIFI_MODE,
+ 0x00, // OFF
+ ]);
+ }
+
+ async setWiFiChannel(wifiChannel) {
+ await this.sendKissCommand([
+ this.CMD_WIFI_CHN,
+ wifiChannel, // 1-14
+ ]);
+ }
+
+ async setWiFiSSID(wifiSSID) {
+ const encoder = new TextEncoder();
+ const ssidBytes = encoder.encode(wifiSSID);
+
+ // Add null terminator
+ const data = new Uint8Array(ssidBytes.length + 1);
+ data.set(ssidBytes);
+ data[data.length - 1] = 0x00;
+
+ // KISS escape
+ const escaped = [];
+ for (const byte of data) {
+ if (byte === this.FEND) {
+ escaped.push(this.FESC, this.TFEND);
+ } else if (byte === this.FESC) {
+ escaped.push(this.FESC, this.TFESC);
+ } else {
+ escaped.push(byte);
+ }
+ }
+
+ // Send command
+ await this.sendKissCommand([
+ this.CMD_WIFI_SSID,
+ ...escaped,
+ ]);
+ }
+
+ async setWiFiPSK(wifiPSK) {
+ if (wifiPSK == null) {
+ // Clear PSK
+ await this.sendKissCommand([
+ this.CMD_WIFI_PSK,
+ 0x00
+ ]);
+ return;
+ }
+
+ const encoder = new TextEncoder();
+ const pskBytes = encoder.encode(wifiPSK);
+
+ // Enforce firmware length rules (8–32 characters)
+ if (pskBytes.length < 8 || pskBytes.length > 32) {
+ throw new Error("Invalid PSK length (must be 8–32 bytes)");
+ }
+
+ // Add null terminator
+ const data = new Uint8Array(pskBytes.length + 1);
+ data.set(pskBytes);
+ data[data.length - 1] = 0x00;
+
+ // KISS escape
+ const escaped = [];
+ for (const byte of data) {
+ if (byte === this.FEND) {
+ escaped.push(this.FESC, this.TFEND);
+ } else if (byte === this.FESC) {
+ escaped.push(this.FESC, this.TFESC);
+ } else {
+ escaped.push(byte);
+ }
+ }
+
+ // Send command
+ await this.sendKissCommand([
+ this.CMD_WIFI_PSK,
+ ...escaped,
+ ]);
+ }
+
+ async setWiFiIP(wifiIP) {
+ if (wifiIP == null) {
+ // Clear IP → 0.0.0.0
+ await this.sendKissCommand([
+ this.CMD_WIFI_IP,
+ 0x00, 0x00, 0x00, 0x00
+ ]);
+ return;
+ }
+
+ if (typeof wifiIP !== "string") {
+ throw new TypeError("Invalid IP address (not a string)");
+ }
+
+ const octets = wifiIP.split(".");
+ if (octets.length !== 4) {
+ throw new Error("Invalid IP address length");
+ }
+
+ const ipBytes = new Uint8Array(4);
+
+ for (let i = 0; i < 4; i++) {
+ const octet = Number(octets[i]);
+
+ if (!Number.isInteger(octet) || octet < 0 || octet > 255) {
+ throw new Error("Invalid IP octet value");
+ }
+
+ ipBytes[i] = octet;
+ }
+
+ // KISS escape (same as PSK logic)
+ const escaped = [];
+ for (const byte of ipBytes) {
+ if (byte === this.KISS_FEND) {
+ escaped.push(this.KISS_FESC, this.KISS_TFEND);
+ } else if (byte === this.KISS_FESC) {
+ escaped.push(this.KISS_FESC, this.KISS_TFESC);
+ } else {
+ escaped.push(byte);
+ }
+ }
+
+ // Send command exactly like PSK does
+ await this.sendKissCommand([
+ this.CMD_WIFI_IP,
+ ...escaped,
+ ]);
+ }
+
+ async setWiFiNM(wifiNM) {
+ if (wifiNM == null) {
+ // Clear netmask → 0.0.0.0
+ await this.sendKissCommand([
+ this.CMD_WIFI_NM,
+ 0x00, 0x00, 0x00, 0x00
+ ]);
+ return;
+ }
+
+ if (typeof wifiNM !== "string") {
+ throw new TypeError("Invalid netmask (not a string)");
+ }
+
+ const octets = wifiNM.split(".");
+ if (octets.length !== 4) {
+ throw new Error("Invalid netmask length");
+ }
+
+ const nmBytes = new Uint8Array(4);
+
+ for (let i = 0; i < 4; i++) {
+ const octet = Number(octets[i]);
+
+ if (!Number.isInteger(octet) || octet < 0 || octet > 255) {
+ throw new Error("Invalid netmask octet value");
+ }
+
+ nmBytes[i] = octet;
+ }
+
+ // Send using same KISS pipeline as PSK/IP
+ await this.sendKissCommand([
+ this.CMD_WIFI_NM,
+ ...nmBytes
+ ]);
+ }
+
async readDisplay() {
const response = await this.sendCommand(this.CMD_DISP_READ, [
@@ -759,6 +946,20 @@ class RNode {
]);
}
+ async setDisplayIntensity(intensity) {
+ await this.sendKissCommand([
+ this.CMD_DISP_INT,
+ intensity & 0xFF,
+ ]);
+ }
+
+ async setDisplayTimeout(timeout) {
+ await this.sendKissCommand([
+ this.CMD_DISP_BLNK,
+ timeout & 0xFF,
+ ]);
+ }
+
async startDisplayReconditioning() {
await this.sendKissCommand([
this.CMD_DISP_RCND,
@@ -855,12 +1056,29 @@ class ROM {
static ADDR_CHKSUM = 0x0B
static ADDR_SIGNATURE = 0x1B
static ADDR_INFO_LOCK = 0x9B
+
static ADDR_CONF_SF = 0x9C
static ADDR_CONF_CR = 0x9D
static ADDR_CONF_TXP = 0x9E
static ADDR_CONF_BW = 0x9F
static ADDR_CONF_FREQ = 0xA3
static ADDR_CONF_OK = 0xA7
+ static ADDR_CONF_BT = 0xB0
+ static ADDR_CONF_DSET = 0xB1
+ static ADDR_CONF_DINT = 0xB2
+ static ADDR_CONF_DADR = 0xB3
+ static ADDR_CONF_DBLK = 0xB4
+ static ADDR_CONF_DROT = 0xB8
+ static ADDR_CONF_PSET = 0xB5
+ static ADDR_CONF_PINT = 0xB6
+ static ADDR_CONF_BSET = 0xB7
+ static ADDR_CONF_DIA = 0xB9
+ static ADDR_CONF_WIFI = 0xBA
+ static ADDR_CONF_WCHN = 0xBB
+ static ADDR_CONF_SSID = 0x00
+ static ADDR_CONF_PSK = 0x21
+ static ADDR_CONF_IP = 0x42
+ static ADDR_CONF_NM = 0x46
static INFO_LOCK_BYTE = 0x73
static CONF_OK_BYTE = 0x73