From e0754f1f0258008961720a3bacefd582555c1fcf Mon Sep 17 00:00:00 2001 From: acidvegas Date: Mon, 29 Apr 2024 14:15:38 -0400 Subject: [PATCH] Added some firmware hacking documentation for customization, white-space cleanup, etc --- FIRMWARE_HACKS.md | 39 +++++++++++++++++++++++++++++++++++++++ README.md | 2 ++ meshirc.py | 23 ++++++++++++----------- meshtastic_serial.py | 28 +++++++++++----------------- 4 files changed, 64 insertions(+), 28 deletions(-) create mode 100644 FIRMWARE_HACKS.md diff --git a/FIRMWARE_HACKS.md b/FIRMWARE_HACKS.md new file mode 100644 index 0000000..3e00759 --- /dev/null +++ b/FIRMWARE_HACKS.md @@ -0,0 +1,39 @@ +# Meshtastic Firmware Hacks + +### Custom Boot Logo & Message +- Download & install [PlatformIO](https://platformio.org/platformio-ide) + +- `git clone https://github.com/meshtastic/firmware.git` + +- `cd firmware && git submodule update --init` + +- Use [XMB Viewer](https://windows87.github.io/xbm-viewer-converter/) to convert an image to XMB + +- The data from this goes in `firmware/src/graphics/img/icon.xbm` + +### Custom boot message +- Navigate to `firmware/src/graphics/Screen.cpp` + +- Find & replace `const char *title = "meshtastic.org";` with your custom message. + +### Custom screen color + - Navigate to `src/graphics/TFTDisplay.cpp` + + - Find & replace `#define TFT_MESH COLOR565(0x67, 0xEA, 0x94)` with your custom color. + + ### Custom alert sound (for T-Deck & devices with a buzzer) + - From the mobile app, click the 3 dots on the top right, and select `Radio configuration` + - Under `Module configuration`, select `External Notification` +- Scroll down & you will see a `Ringtone` option that takes [RTTTL](https://en.wikipedia.org/wiki/Ring_Tone_Text_Transfer_Language) formatted tones. + +As far as I know, at the time of writing this, the onyl way to change the Ringtone is from the App... + + + ## Compile & flash firmware + - Select `PlatformIO: Pick Project Environment` & select your board. + - Run `PLatformIO: Build` to compile the firmware. + - Place device in DFU mode & plug in to the computer + - Do `PlatformIO: Upload` to send the firmware to the device + - Press the RESET button or reboot your device. + + See [here](https://meshtastic.org/docs/development/firmware/build/) for more information building & flashing custom firmware. \ No newline at end of file diff --git a/README.md b/README.md index a8fea95..1b43d04 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ The goal here is to create simple & clean modules to interface with the hardware The hardware I am experimenting with: [Lilygo T-Deck](https://www.lilygo.cc/products/t-deck), [Lilygo T-Beam](https://www.lilygo.cc/products/t-beam-v1-1-esp32-lora-module), [Heltec Lora 32 v3](https://heltec.org/project/wifi-lora-32-v3/), and [RAK Wireless 4631](https://store.rakwireless.com/products/wisblock-core-modules?variant=42440631419078) +## Notes to self & developers +- The node id formula is: f'!{hex(node_num)[2:]}' ## Hardware & Software related Issues - T-Deck must have Wifi turned off when going mobile. Upon leaving my house with WiFi still enabled, the UI & connection was EXTREMELY laggy & poor. Couldn't even type well... diff --git a/meshirc.py b/meshirc.py index 002759f..d6033fb 100644 --- a/meshirc.py +++ b/meshirc.py @@ -7,6 +7,7 @@ import logging import ssl import time +# EF576MkXA3aEURbCfNn6p0FfZdua4I # Formatting Control Characters / Color Codes bold = '\x02' @@ -44,7 +45,7 @@ def color(msg: str, foreground: str, background: str = None) -> str: :param foreground: The foreground color to use. :param background: The background color to use. ''' - + return f'\x03{foreground},{background}{msg}{reset}' if background else f'\x03{foreground}{msg}{reset}' @@ -63,7 +64,7 @@ class Bot(): :param chan: The channel to send the ACTION to. :param msg: The message to send to the channel. ''' - + await self.sendmsg(chan, f'\x01ACTION {msg}\x01') @@ -73,7 +74,7 @@ class Bot(): :param data: The raw data to send to the IRC server. (512 bytes max including crlf) ''' - + await self.writer.write(data[:510].encode('utf-8') + b'\r\n') @@ -84,13 +85,13 @@ class Bot(): :param target: The target to send the PRIVMSG to. (channel or user) :param msg: The message to send to the target. ''' - + await self.raw(f'PRIVMSG {target} :{msg}') async def connect(self): '''Connect to the IRC server.''' - + while True: try: options = { @@ -124,7 +125,7 @@ class Bot(): :param data: The data received from the IRC server. ''' - + parts = data.split() ident = parts[0][1:] @@ -146,7 +147,7 @@ class Bot(): if len(message) > 255: await self.sendmsg(target, color('Message exceeds 255 bytes nerd!', red)) # TODO: Send a meshtastic message (We have to ensure our outbounds from IRC don't loop back into IRC) - + self.last = time.time() # Update the last command time if it starts with ! character to prevent command flooding @@ -156,9 +157,9 @@ class Bot(): :param data: The data received from the IRC server. ''' - + logging.info(data) - + try: parts = data.split() @@ -207,7 +208,7 @@ if __name__ == '__main__': parser.add_argument('--ssl', action='store_true', help='Use SSL for the connection.') parser.add_argument('--key', default='', help='The key (password) for the IRC channel, if required.') args = parser.parse_args() - + if not args.channel.startswith('#'): channel = '#' + args.channel @@ -220,4 +221,4 @@ if __name__ == '__main__': bot = Bot() - asyncio.run(bot.connect()) \ No newline at end of file + asyncio.run(bot.connect()) diff --git a/meshtastic_serial.py b/meshtastic_serial.py index 9236a04..27566ed 100644 --- a/meshtastic_serial.py +++ b/meshtastic_serial.py @@ -17,24 +17,18 @@ except ImportError: try: from pubsub import pub except ImportError: - raise ImportError('pubsub library not found (pip install pypubsub)') # Confirm this Pypi package name... + raise ImportError('pubsub library not found (pip install pypubsub)') # Initialize logging logging.basicConfig(level=logging.INFO, format='%(asctime)s | %(levelname)9s | %(funcName)s | %(message)s', datefmt='%Y-%m-%d %I:%M:%S') -def now(): - '''Returns the current date and time in a formatted string''' - - return time.strftime('%Y-%m-%d %H:%M:%S') - - class MeshtasticClient(object): def __init__(self): - self.interface = None # We will define the interface in the connect() function - self.me = {} # We will populate this with the event_connect() callback - self.nodes = {} # Nodes will populate with the event_node() callback + self.interface = None + self.me = {} + self.nodes = {} def connect(self, option: str, value: str): @@ -71,7 +65,7 @@ class MeshtasticClient(object): break - def send(self, message: str): + def sendmsg(self, message: str, destination: int, channelIndex: int = 0): ''' Send a message to the Meshtastic interface @@ -82,7 +76,7 @@ class MeshtasticClient(object): logging.warning('Message exceeds 255 characters') message = message[:255] - self.interface.sendText(message) + self.interface.sendText(message, destination, wantAck=True, channelIndex=channelIndex) # Do we need wantAck? logging.info(f'Sent broadcast message: {message}') @@ -121,7 +115,7 @@ class MeshtasticClient(object): :param interface: Meshtastic interface ''' - logging.info(f'Data update: {data}') + logging.info(f'Data update: {packet}') def event_disconnect(self, interface, topic=pub.AUTO_TOPIC): @@ -149,7 +143,7 @@ class MeshtasticClient(object): self.nodes[node['num']] = node - logging.info(f'Node found: {node["user"]["id"]} - {node["user"]["shortName"].ljust(4)} - {node["user"]["longName"]}') + logging.info(f'Node recieved: {node["user"]["id"]} - {node["user"]["shortName"].ljust(4)} - {node["user"]["longName"]}') def event_position(self, packet: dict, interface): @@ -161,7 +155,7 @@ class MeshtasticClient(object): ''' sender = packet['from'] - msg = packet['decoded']['payload'].hex() + msg = packet['decoded']['payload'].hex() # What exactly is contained in this payload? id = self.nodes[sender]['user']['id'] if sender in self.nodes else '!unk ' name = self.nodes[sender]['user']['longName'] if sender in self.nodes else 'UNK' longitude = packet['decoded']['position']['longitudeI'] / 1e7 @@ -170,7 +164,7 @@ class MeshtasticClient(object): snr = packet['rxSnr'] rssi = packet['rxRssi'] - logging.info(f'{id} - {name}: {longitude}, {latitude}, {altitude}m (SNR: {snr}, RSSI: {rssi}) - {msg}') + logging.info(f'Position recieved: {id} - {name}: {longitude}, {latitude}, {altitude}m (SNR: {snr}, RSSI: {rssi}) - {msg}') def event_text(self, packet: dict, interface): @@ -187,7 +181,7 @@ class MeshtasticClient(object): name = self.nodes[sender]['user']['longName'] if sender in self.nodes else 'UNK' target = self.nodes[to]['user']['longName'] if to in self.nodes else 'UNK' - logging.info(f'{id} {name} -> {target}: {msg}') + logging.info(f'Message recieved: {id} {name} -> {target}: {msg}') print(packet)