Settings not retained over serial interface (Windows WSL)

I’m having trouble getting settings to “stick” when setting them from the serial interface. I’ve tried --set-owner, --set wifi_ssid, and --set wifi_password all with no luck on the serial interface, although setting the owner name works OK on the Android interface. I recently re-flashed firmware-tbeam-1.2.30.80e4bc6.bin in order to try to get the web UI up and running. Before that, I was able to use --set wifi_ssid and --set wifi_password, and it worked OK.

Here’s a transcript of my session with --debug enabled:

jdstroy@laptop:~/ttgo$ sudo meshtastic --port /dev/ttyS3 --debug --set wifi_ssid 'exampe_ssid' --set wifi_password 'example_password' --set wifi_ap_mode false --info
DEBUG:root:Not logging serial output
DEBUG:root:Connecting to /dev/ttyS3
DEBUG:root:Sending: want_config_id: 1452937022
DEBUG:root:Received myinfo: my_node_num: 84682428 has_gps: true num_bands: 13 firmware_version: "1.2.30.80e4bc6" reboot_count: 54 message_timeout_msec: 300000 min_app_version: 20200 max_channels: 8
DEBUG:root:Received nodeinfo: {'num': 84682428, 'user': {'id': '!050c26bc', 'longName': 'Yell', 'shortName': 'Yll', 'macaddr': 'PGEFDCa8', 'hwModel': 'TBEAM'}, 'position': {'latitudeI': 302317541, 'longitudeI': -978873096, 'altitude': 306, 'time': 1621878012, 'latitude': 30.2317541, 'longitude': -97.8873096}, 'lastHeard': 1621878012}
DEBUG:root:Config complete ID 1452937022
DEBUG:root:Serializing protobuf as data: get_radio_request: true
DEBUG:root:Sending: packet { to: 84682428 decoded { portnum: ADMIN_APP payload: " \001" want_response: true } id: 604535689 hop_limit: 3 want_ack: true }
DEBUG:root:Received radio config, now fetching channels...
DEBUG:root:Requesting channel 0
DEBUG:root:Serializing protobuf as data: get_channel_request: 1
DEBUG:root:Sending: packet { to: 84682428 decoded { portnum: ADMIN_APP payload: "0\001" want_response: true } id: 604535690 hop_limit: 3 want_ack: true }
DEBUG:root:Publishing meshtastic.receive.admin: packet={'from': 84682428, 'to': 84682428, 'decoded': {'portnum': 'ADMIN_APP', 'payload': b'*\x18\n\x16\x08\n\x10\xe8\x020\x84\x07P\xff\x93\xeb\xdc\x03x\x01\x80\x02\x01\x90\x02\n', 'requestId': 604535689, 'admin': {'getRadioResponse': {'preferences': {'positionBroadcastSecs': 10, 'sendOwnerInterval': 360, 'phoneTimeoutSecs': 900, 'lsSecs': 999999999, 'region': 'US', 'locationShare': 'LocEnabled', 'gpsUpdateInterval': 10}}, 'raw': get_radio_response { preferences { position_broadcast_secs: 10 send_owner_interval: 360 phone_timeout_secs: 900 ls_secs: 999999999 region: US location_share: LocEnabled gps_update_interval: 10 } } }}, 'id': 1720763711, 'rxTime': 1621878012, 'hopLimit': 3, 'priority': 'RELIABLE', 'raw': from: 84682428 to: 84682428 decoded { portnum: ADMIN_APP payload: "*\030\n\026\010\n\020\350\0020\204\007P\377\223\353\334\003x\001\200\002\001\220\002\n" request_id: 604535689 } id: 1720763711 rx_time: 1621878012 hop_limit: 3 priority: RELIABLE , 'fromId': '!050c26bc', 'toId': '!050c26bc'} 
DEBUG:root:Received channel settings { modem_config: Bw125Cr48Sf4096 psk: "\001" } role: PRIMARY
DEBUG:root:Requesting channel 1
DEBUG:root:Serializing protobuf as data: get_channel_request: 2
DEBUG:root:Sending: packet { to: 84682428 decoded { portnum: ADMIN_APP payload: "0\002" want_response: true } id: 604535691 hop_limit: 3 want_ack: true }
DEBUG:root:Publishing meshtastic.receive.admin: packet={'from': 84682428, 'to': 84682428, 'decoded': {'portnum': 'ADMIN_APP', 'payload': b':\t\x12\x05\x18\x03"\x01\x01\x18\x01', 'requestId': 604535690, 'admin': {'getChannelResponse': {'settings': {'modemConfig': 'Bw125Cr48Sf4096', 'psk': 'AQ=='}, 'role': 'PRIMARY'}, 'raw': get_channel_response { settings { modem_config: Bw125Cr48Sf4096 psk: "\001" } role: PRIMARY } }}, 'id': 1720763712, 'rxTime': 1621878012, 'hopLimit': 3, 'priority': 'RELIABLE', 'raw': from: 84682428 to: 84682428 decoded { portnum: ADMIN_APP payload: ":\t\022\005\030\003\"\001\001\030\001" request_id: 604535690 } id: 1720763712 rx_time: 1621878012 hop_limit: 3 priority: RELIABLE , 'fromId': '!050c26bc', 'toId': '!050c26bc'} 
DEBUG:root:Received channel index: 1 settings { }
DEBUG:root:Finished downloading channels
Connected to radio
DEBUG:root:Sending heartbeat, interval 450.0
DEBUG:root:Serializing protobuf as data: time: 1621878011
DEBUG:root:Sending: packet { to: 4294967295 decoded { portnum: POSITION_APP payload: "M\373\344\253`" } id: 604535692 hop_limit: 3 }
Set wifi_ssid to exampe_ssid
DEBUG:root:Sending: 
Set wifi_password to example_password
DEBUG:root:Publishing meshtastic.receive.admin: packet={'from': 84682428, 'to': 84682428, 'decoded': {'portnum': 'ADMIN_APP', 'payload': b':\x04\x08\x01\x12\x00', 'requestId': 604535691, 'admin': {'getChannelResponse': {'index': 1, 'settings': {}}, 'raw': get_channel_response { index: 1 settings { } } }}, 'id': 1720763713, 'rxTime': 1621878012, 'hopLimit': 3, 'priority': 'RELIABLE', 'raw': from: 84682428 to: 84682428 decoded { portnum: ADMIN_APP payload: ":\004\010\001\022\000" request_id: 604535691 } id: 1720763713 rx_time: 1621878012 hop_limit: 3 priority: RELIABLE , 'fromId': '!050c26bc', 'toId': '!050c26bc'} 
Set wifi_ap_mode to false
Writing modified preferences to device
DEBUG:root:Serializing protobuf as data: set_radio { preferences { position_broadcast_secs: 10 send_owner_interval: 360 phone_timeout_secs: 900 ls_secs: 999999999 wifi_ssid: "exampe_ssid" wifi_password: "example_password" region: US location_share: LocEnabled gps_update_interval: 10 } }
DEBUG:root:Sending: packet { to: 84682428 decoded { portnum: ADMIN_APP payload: "\n7\n5\010\n\020\350\0020\204\007P\377\223\353\334\003b\013exampe_ssidj\020example_passwordx\001\200\002\001\220\002\n" } id: 604535693 hop_limit: 3 want_ack: true }
DEBUG:root:Wrote config

Owner: Yell (Yll)

My info: { "myNodeNum": 84682428, "hasGps": true, "numBands": 13, "firmwareVersion": "1.2.30.80e4bc6", "rebootCount": 54, "messageTimeoutMsec": 300000, "minAppVersion": 20200, "maxChannels": 8 }

Nodes in mesh:
  {'num': 84682428, 'user': {'id': '!050c26bc', 'longName': 'Yell', 'shortName': 'Yll', 'macaddr': 'PGEFDCa8', 'hwModel': 'TBEAM'}, 'position': {'latitudeI': 302317541, 'longitudeI': -978873096, 'altitude': 306, 'time': 1621878012, 'latitude': 30.2317541, 'longitude': -97.8873096}, 'lastHeard': 1621878012}

Preferences: { "positionBroadcastSecs": 10, "sendOwnerInterval": 360, "phoneTimeoutSecs": 900, "lsSecs": 999999999, "wifiSsid": "exampe_ssid", "wifiPassword": "example_password", "region": "US", "locationShare": "LocEnabled", "gpsUpdateInterval": 10 }

Channels:
  PRIMARY psk=default { "modemConfig": "Bw125Cr48Sf4096", "psk": "AQ==" }

Primary channel URL: https://www.meshtastic.org/d/#CgUYAyIBAQ

DEBUG:root:Closing stream
DEBUG:root:Sending: disconnect: true
DEBUG:root:reader is exiting
DEBUG:root:Closing our port
jdstroy@laptop:~/ttgo$ sudo meshtastic --port /dev/ttyS3 --debug --info
DEBUG:root:Not logging serial output
DEBUG:root:Connecting to /dev/ttyS3
DEBUG:root:Sending: want_config_id: 3266087387
DEBUG:root:Received myinfo: my_node_num: 84682428 has_gps: true num_bands: 13 firmware_version: "1.2.30.80e4bc6" reboot_count: 55 message_timeout_msec: 300000 min_app_version: 20200 max_channels: 8
DEBUG:root:Received nodeinfo: {'num': 84682428, 'user': {'id': '!050c26bc', 'longName': 'Yell', 'shortName': 'Yll', 'macaddr': 'PGEFDCa8', 'hwModel': 'TBEAM'}, 'position': {'latitudeI': 302320799, 'longitudeI': -978871813, 'altitude': 306, 'time': 1621878026, 'latitude': 30.2320799, 'longitude': -97.8871813}, 'lastHeard': 1621878026}
DEBUG:root:Config complete ID 3266087387
DEBUG:root:Serializing protobuf as data: get_radio_request: true
DEBUG:root:Sending: packet { to: 84682428 decoded { portnum: ADMIN_APP payload: " \001" want_response: true } id: 1634340353 hop_limit: 3 want_ack: true }
DEBUG:root:Received radio config, now fetching channels...
DEBUG:root:Requesting channel 0
DEBUG:root:Serializing protobuf as data: get_channel_request: 1
DEBUG:root:Sending: packet { to: 84682428 decoded { portnum: ADMIN_APP payload: "0\001" want_response: true } id: 1634340354 hop_limit: 3 want_ack: true }
DEBUG:root:Publishing meshtastic.receive.admin: packet={'from': 84682428, 'to': 84682428, 'decoded': {'portnum': 'ADMIN_APP', 'payload': b'*\x18\n\x16\x08\n\x10\xe8\x020\x84\x07P\xff\x93\xeb\xdc\x03x\x01\x80\x02\x01\x90\x02\n', 'requestId': 1634340353, 'admin': {'getRadioResponse': {'preferences': {'positionBroadcastSecs': 10, 'sendOwnerInterval': 360, 'phoneTimeoutSecs': 900, 'lsSecs': 999999999, 'region': 'US', 'locationShare': 'LocEnabled', 'gpsUpdateInterval': 10}}, 'raw': get_radio_response { preferences { position_broadcast_secs: 10 send_owner_interval: 360 phone_timeout_secs: 900 ls_secs: 999999999 region: US location_share: LocEnabled gps_update_interval: 10 } } }}, 'id': 1060614845, 'rxTime': 1621878026, 'hopLimit': 3, 'priority': 'RELIABLE', 'raw': from: 84682428 to: 84682428 decoded { portnum: ADMIN_APP payload: "*\030\n\026\010\n\020\350\0020\204\007P\377\223\353\334\003x\001\200\002\001\220\002\n" request_id: 1634340353 } id: 1060614845 rx_time: 1621878026 hop_limit: 3 priority: RELIABLE , 'fromId': '!050c26bc', 'toId': '!050c26bc'} 
DEBUG:root:Received channel settings { modem_config: Bw125Cr48Sf4096 psk: "\001" } role: PRIMARY
DEBUG:root:Requesting channel 1
DEBUG:root:Serializing protobuf as data: get_channel_request: 2
DEBUG:root:Sending: packet { to: 84682428 decoded { portnum: ADMIN_APP payload: "0\002" want_response: true } id: 1634340355 hop_limit: 3 want_ack: true }
DEBUG:root:Publishing meshtastic.receive.admin: packet={'from': 84682428, 'to': 84682428, 'decoded': {'portnum': 'ADMIN_APP', 'payload': b':\t\x12\x05\x18\x03"\x01\x01\x18\x01', 'requestId': 1634340354, 'admin': {'getChannelResponse': {'settings': {'modemConfig': 'Bw125Cr48Sf4096', 'psk': 'AQ=='}, 'role': 'PRIMARY'}, 'raw': get_channel_response { settings { modem_config: Bw125Cr48Sf4096 psk: "\001" } role: PRIMARY } }}, 'id': 1060614846, 'rxTime': 1621878026, 'hopLimit': 3, 'priority': 'RELIABLE', 'raw': from: 84682428 to: 84682428 decoded { portnum: ADMIN_APP payload: ":\t\022\005\030\003\"\001\001\030\001" request_id: 1634340354 } id: 1060614846 rx_time: 1621878026 hop_limit: 3 priority: RELIABLE , 'fromId': '!050c26bc', 'toId': '!050c26bc'} 
DEBUG:root:Received channel index: 1 settings { }
DEBUG:root:Finished downloading channels
Connected to radio
DEBUG:root:Sending heartbeat, interval 450.0
DEBUG:root:Serializing protobuf as data: time: 1621878026
DEBUG:root:Sending: packet { to: 4294967295 decoded { portnum: POSITION_APP payload: "M\n\345\253`" } id: 1634340356 hop_limit: 3 }
DEBUG:root:Sending: 

Owner: Yell (Yll)
DEBUG:root:Publishing meshtastic.receive.admin: packet={'from': 84682428, 'to': 84682428, 'decoded': {'portnum': 'ADMIN_APP', 'payload': b':\x04\x08\x01\x12\x00', 'requestId': 1634340355, 'admin': {'getChannelResponse': {'index': 1, 'settings': {}}, 'raw': get_channel_response { index: 1 settings { } } }}, 'id': 1060614847, 'rxTime': 1621878026, 'hopLimit': 3, 'priority': 'RELIABLE', 'raw': from: 84682428 to: 84682428 decoded { portnum: ADMIN_APP payload: ":\004\010\001\022\000" request_id: 1634340355 } id: 1060614847 rx_time: 1621878026 hop_limit: 3 priority: RELIABLE , 'fromId': '!050c26bc', 'toId': '!050c26bc'} 

My info: { "myNodeNum": 84682428, "hasGps": true, "numBands": 13, "firmwareVersion": "1.2.30.80e4bc6", "rebootCount": 55, "messageTimeoutMsec": 300000, "minAppVersion": 20200, "maxChannels": 8 }

Nodes in mesh:
  {'num': 84682428, 'user': {'id': '!050c26bc', 'longName': 'Yell', 'shortName': 'Yll', 'macaddr': 'PGEFDCa8', 'hwModel': 'TBEAM'}, 'position': {'latitudeI': 302320799, 'longitudeI': -978871813, 'altitude': 306, 'time': 1621878026, 'latitude': 30.2320799, 'longitude': -97.8871813}, 'lastHeard': 1621878026}

Preferences: { "positionBroadcastSecs": 10, "sendOwnerInterval": 360, "phoneTimeoutSecs": 900, "lsSecs": 999999999, "region": "US", "locationShare": "LocEnabled", "gpsUpdateInterval": 10 }

Channels:
  PRIMARY psk=default { "modemConfig": "Bw125Cr48Sf4096", "psk": "AQ==" }

Primary channel URL: https://www.meshtastic.org/d/#CgUYAyIBAQ

DEBUG:root:Closing stream
DEBUG:root:Sending: disconnect: true
DEBUG:root:reader is exiting
DEBUG:root:Closing our port

Notice Preferences has non-default values (from the phone), but didn’t retain the wifi settings set in the previous session.

Python client version is 1.2.35. Device firmware version is 1.2.30.80e4bc6 (as shown in output above).

Ideas?

I flashed one of my TBeams to firmware-tbeam-1.2.30.80e4bc6.bin and upgraded my python client to 1.2.35. I was unable to replicate this error. I’m sorry it’s no help! I did notice in your logs it says originally that the ssid/password are set correctly, how soon after the original command did you run --debug --info? I know some have had issues with timing out on the CLI recently.

The only difference in the commands I tested was I didn’t run sudo meshtastic I was able to just run meshtastic --debug --info.

I ran meshtastic --info almost immediately after. The first time that the prefs are printed out is due to the --info added after the --set options, but I don’t think the printout is accurate; a cursory glance over the code and sifting through the debug messages hints that the data may be whatever’s written/cached on the python client – not necessarily what the device wrote to nonvolatile storage.

True, try meshtastic --get wifi_ssid that might give you different results than info.

Definitely not set.

On a hunch, I took a different approach. I fired up python (sudo python3) and tried something like this (replicating the functional parts of __main__.py):

import meshtastic;
import time;

si = meshtastic.SerialInterface(devPath='/dev/ttyS3')
node = si.getNode('^local');
rc = node.radioConfig
rc.preferences.wifi_ssid = 'example_ssid';
rc.preferences.wifi_password = 'example_password';
node.writeConfig();
time.sleep(5);
node.reboot();

This seemed to apply my changes. Running meshtastic --info now produces the results that I expect. This seems to hint at some kind of oddity with writing the data to SPIFFS and resetting the ESP32. Maybe there’s a cache layer in RAM that needs to be flushed? Not exactly sure.

I’m doing this on my Windows 10 laptop, running WSL, so that might be another wrench to throw into the mix. It seems to me that each time there’s some serial port handshaking, the ESP32 resets (i.e. if I do sudo cat /dev/ttyS3, I can see the serial output; hitting Ctrl-C, however makes the device reset). This also seems to be the case for running meshtastic --port /dev/ttyS3 any time Meshtastic needs to do handshaking stuff on the port (i.e. after the program terminates)… I think this makes sense, in light of the ESP32 / ESP8266 platforms generally hard-wiring the CP21xx USB to serial UART bridge DTR/RTS pins to reset/program the ESP32. I’m not certain if this is expected behavior, or if it’s some oddity that’s in the translation from Linux to Windows/NT caused by WSL. (Oddly, it used to work.)

Perhaps someone can test this and reply back – does the node always reset after running the Meshtastic-python client via the serial port? Is this expected (@geeksville)? If so, does the python client need to wait for the data to sync to NV storage before closing the connection or rebooting the device?

I bet there is something funky in RTS/CTS handling in WSL. It never resets on my real linux machine talking python to the ESP32. Sometime ago we went through a slightly painful problem of fixing reboots when using python natively on windows to talk to the board.

I bet the fix for WSL will lie in changing the following lines in meshtastic/init.py:

        # OS-X/Windows seems to have a bug in its serial driver.  It ignores that we asked for no RTSCTS
        # control and will always drive RTS either high or low (rather than letting the CP102 leave
        # it as an open-collector floating pin).  Since it is going to drive it anyways we want to make
        # sure it is driven low, so that the TBEAM won't reset
        # Linux does this properly, so don't apply this hack (because it makes the reset button not work)
        if platform.system() != 'Linux':
            self.stream.rts = False

Would you be willing to debug/poke around a bit there and possibly send in a PR? I don’t have WSL (and only barely have Windows) to test with.

perhaps you could check a different property of platform to identify that the code is running on WSL, and in that case apply the same hack. (Because the outer Windows OS driver is probably going to misdrive RTS otherwise)

This is trivial in a shell script; I’m not sure what’s the best way in Python:

[ -c /dev/lxss ] || echo "on WSL(1)"

There’s a few other ways, like:

grep '^Microsoft.*-Microsoft' /proc/version_signature

Probably a close approximation would be:

import stat;
import os;
isWsl1 = stat.S_ISCHR(os.stat('/dev/lxss').st_mode);

Definitely willing to poke around. I’ll give it a try next time I take the T-Beam down from my window and will reply here after doing so.

I’m guessing the change will be something like:

if platform.system() != 'Linux' || is_wsl():
    self.stream.rts = False
1 Like

yah - I bet something in the existing python platform package will have something you can nicely match against (something like OS version or vendor or whatever)

Sent a PR for doing the same hack on WSL1. I was able to confirm that it works on WSL1 – my device no longer resets on exiting the Python API client; please exercise it on Linux and OS X. (As per comments, WSL2 currently has no support for UART serial ports or USB pass-through, so for now, it’s not usable with Meshtastic via the serial interface.)

I also sent a different PR for fixing the help text for --subnet while I was in the code.

1 Like