mirror of
https://github.com/SpudGunMan/meshing-around.git
synced 2026-03-28 17:32:36 +01:00
Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fa5928537 | ||
|
|
f12198b140 | ||
|
|
0d44ffb635 | ||
|
|
c11ebf1443 | ||
|
|
b94a5ebd8d | ||
|
|
3392d2d5a8 | ||
|
|
1df3a7aaa2 | ||
|
|
9a11214208 | ||
|
|
0a4f101370 | ||
|
|
5f3c32dc00 | ||
|
|
74cb135c6c | ||
|
|
a20e520501 | ||
|
|
23e0e4c6a0 | ||
|
|
10918546d6 | ||
|
|
cf16cc6606 | ||
|
|
3b73b665d6 | ||
|
|
993fd760af | ||
|
|
a029334576 | ||
|
|
eb8143f298 | ||
|
|
c756b447ac | ||
|
|
cef05e061c | ||
|
|
c85d517b91 | ||
|
|
170d1a6a45 | ||
|
|
8d2313cfb1 | ||
|
|
ed8636f5a5 | ||
|
|
b95d94f06f | ||
|
|
f7cdf446bf | ||
|
|
28e8e2705a | ||
|
|
9bc6f6f661 | ||
|
|
2630310210 | ||
|
|
3fae42305c | ||
|
|
9cc8dd7143 | ||
|
|
7ffa9d5309 | ||
|
|
30d2b996c0 | ||
|
|
49c098ef0b | ||
|
|
afa41c6ecd | ||
|
|
8861179cb2 | ||
|
|
f32ceb0383 | ||
|
|
9a380964aa | ||
|
|
180a8261ca | ||
|
|
0536657c8e | ||
|
|
c5a2330dd1 | ||
|
|
dc0b5be387 | ||
|
|
a1f43a5e94 | ||
|
|
b05a817769 | ||
|
|
f7187fdf27 | ||
|
|
cca51d68dd | ||
|
|
21804cc975 | ||
|
|
7a9ee27336 | ||
|
|
0c637226b2 | ||
|
|
555b14ddc0 | ||
|
|
656c23c631 | ||
|
|
bb591257c9 | ||
|
|
364a5c5c67 | ||
|
|
8cb05d38db | ||
|
|
f9fe13f322 |
60
README.md
60
README.md
@@ -80,7 +80,7 @@ The code is under active development, so make sure to pull the latest changes re
|
||||
#### Docker Installation
|
||||
If you prefer to use Docker, follow these steps:
|
||||
|
||||
1. Ensure your serial port is properly shared and the GPU is configured if using LLM in docker with [NVIDIA](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/docker-specialized.html).
|
||||
1. Ensure your serial port is properly shared.
|
||||
2. Build the Docker image:
|
||||
```sh
|
||||
cd meshing-around
|
||||
@@ -139,7 +139,7 @@ ignoreDefaultChannel = False # ignoreDefaultChannel, the bot will ignore the def
|
||||
```
|
||||
|
||||
### Location Settings
|
||||
The weather forecasting defaults to NOAA, for locations outside the USA, you can set `UseMeteoWxAPI` to `True`, to use a global weather API. The `lat` and `lon` are default values when a node has no location data. It is also the default (or value when none found for user) for Sentry, all NOAA, repeater lookup, etc.
|
||||
The weather forecasting defaults to NOAA, for locations outside the USA, you can set `UseMeteoWxAPI` to `True`, to use a global weather API. The `lat` and `lon` are default values when a node has no location data, as well as the default for all NOAA, repeater lookup. It is also the center of radius for Sentry.
|
||||
|
||||
```ini
|
||||
[location]
|
||||
@@ -151,7 +151,7 @@ riverListDefault = # NOAA Hydrology data, unique identifiers, LID or USGS ID
|
||||
```
|
||||
|
||||
### Module Settings
|
||||
Modules can be enabled or disabled as needed.
|
||||
Modules can be enabled or disabled as needed. They are essentally larger functions of code which you may not want on your mesh or in memory space.
|
||||
|
||||
```ini
|
||||
[bbs]
|
||||
@@ -184,7 +184,7 @@ sentryIgnoreList = # list of ignored nodes numbers ex: 2813308004,4258675309
|
||||
```
|
||||
|
||||
### E-Mail / SMS Settings
|
||||
To enable connectivity with SMTP/IMAP.
|
||||
To enable connectivity with SMTP allows messages from meshtastic into SMTP. The term SMS here is for connection via [carrier email](https://avtech.com/articles/138/list-of-email-to-sms-addresses/)
|
||||
|
||||
```ini
|
||||
[smtp]
|
||||
@@ -203,10 +203,8 @@ Traps the following ("emergency", "911", "112", "999", "police", "fire", "ambula
|
||||
|
||||
```ini
|
||||
[emergencyHandler]
|
||||
# enable or disable the emergency response handler
|
||||
enabled = True
|
||||
# channel to send a message to when the emergency handler is triggered
|
||||
alert_channel = 2
|
||||
enabled = True # enable or disable the emergency response handler
|
||||
alert_channel = 2 # channel to send a message to when the emergency handler is triggered
|
||||
alert_interface = 1
|
||||
```
|
||||
|
||||
@@ -263,6 +261,7 @@ llmEnableHistory = True # enable history for the LLM model to use in responses a
|
||||
llmContext_fromGoogle = True # enable context from google search results helps with responses accuracy
|
||||
googleSearchResults = 3 # number of google search results to include in the context more results = more compute time
|
||||
```
|
||||
Note for LLM in docker with [NVIDIA](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/docker-specialized.html). Needed for the container with ollama running.
|
||||
|
||||
### Radio Monitoring
|
||||
A module allowing a Hamlib compatible radio to connect to the bot. When functioning, it will message the configured channel with a message of in use. **Requires hamlib/rigctld to be running as a service.**
|
||||
@@ -289,6 +288,7 @@ broadcastCh = 2,4
|
||||
enable_read_news = False
|
||||
news_file_path = news.txt
|
||||
news_random_line = False # only return a single random line from the news file
|
||||
enable_runShellCmd = False # enables running of bash commands runShell.sh demo for sysinfo
|
||||
```
|
||||
|
||||
#### Offline EAS
|
||||
@@ -316,6 +316,8 @@ rtl_fm -f 162425000 -s 22050 | multimon-ng -t raw -a EAS /dev/stdin | python eas
|
||||
#### Newspaper on mesh
|
||||
a newspaper could be built by external scripts. could use Ollama to compile text via news web pages and write news.txt
|
||||
|
||||
you can also enable the line by line (hint just search for the commented lines with a 🐝) to return a string from the [bee movie](https://courses.cs.washington.edu/courses/cse163/20wi/files/lectures/L04/bee-movie.txt) for example adding it alongside news.txt as bee.txt
|
||||
|
||||
### Scheduler
|
||||
In the config.ini enable the module
|
||||
```ini
|
||||
@@ -334,7 +336,7 @@ schedule.every().wednesday.at("19:00").do(lambda: send_message("Net Starting Now
|
||||
```
|
||||
|
||||
#### BBS Link
|
||||
The scheduler also handles the BBL Link Brodcast message, this would be an esxample of a mesh-admin channel on 8 being used to pass BBS post traffic between two bots as the initator, one direction pull.
|
||||
The scheduler also handles the BBS Link Brodcast message, this would be an esxample of a mesh-admin channel on 8 being used to pass BBS post traffic between two bots as the initator, one direction pull.
|
||||
```python
|
||||
# Send bbslink looking for peers every other day at 10:00 using send_message function to channel 8 on device 1
|
||||
schedule.every(2).days.at("10:00").do(lambda: send_message("bbslink MeshBot looking for peers", 8, 0, 1))
|
||||
@@ -345,7 +347,9 @@ bbslink_whitelist = # list of whitelisted nodes numbers ex: 2813308004,425867530
|
||||
```
|
||||
|
||||
### MQTT Notes
|
||||
There is no direct support for MQTT in the code, however, reports from Discord are that using [meshtasticd](https://meshtastic.org/docs/hardware/devices/linux-native-hardware/) with no radio and attaching the bot to the software node, which is MQTT-linked, allows routing.~~There also seems to be a quicker way to enable MQTT by having your bot node with the enabled [serial](https://meshtastic.org/docs/configuration/module/serial/) module with echo enabled and MQTT uplink and downlink. These two~~ methods have been mentioned as allowing MQTT routing for the project. Tested working fully Firmware:2.5.15.79da236 with [mosquitto](https://meshtastic.org/docs/software/integrations/mqtt/mosquitto/).
|
||||
There is no direct support for MQTT in the code, however, reports from Discord are that using [meshtasticd](https://meshtastic.org/docs/hardware/devices/linux-native-hardware/) with no radio and attaching the bot to the software node, which is MQTT-linked, allows routing. Tested working fully Firmware:2.5.15.79da236 with [mosquitto](https://meshtastic.org/docs/software/integrations/mqtt/mosquitto/).
|
||||
|
||||
~~There also seems to be a quicker way to enable MQTT by having your bot node with the enabled [serial](https://meshtastic.org/docs/configuration/module/serial/) module with echo enabled and MQTT uplink and downlink. These two~~
|
||||
|
||||
## Full list of commands for the bot
|
||||
|
||||
@@ -353,28 +357,28 @@ There is no direct support for MQTT in the code, however, reports from Discord a
|
||||
| Command | Description | ✅ Works Off-Grid |
|
||||
|---------|-------------|-
|
||||
| `ping`, `ack` | Return data for signal. Example: `ping 15 #DrivingI5` (activates auto-ping every 20 seconds for count 15) | ✅ |
|
||||
| `test` | Returns like ping but also can be used to test the limits of data buffers `test 4` sends data to the maxBuffer limit (default 220) | ✅ |
|
||||
| `cmd` | Returns the list of commands (the help message) | ✅ |
|
||||
| `history` | Returns the last commands run by user(s) | ✅ |
|
||||
| `lheard` | Returns the last 5 heard nodes with SNR. Can also use `sitrep` | ✅ |
|
||||
| `motd` | Displays the message of the day or sets it. Example: `motd $New Message Of the day` | ✅ |
|
||||
| `sysinfo` | Returns the bot node telemetry info | ✅ |
|
||||
| `test` | used to test the limits of data transfer `test 4` sends data to the maxBuffer limit (default 220) | ✅ |
|
||||
| `whereami` | Returns the address of the sender's location if known |
|
||||
| `whoami` | Returns details of the node asking, also returned when position exchanged 📍 | ✅ |
|
||||
| `whois` | Returns details known about node, more data with bbsadmin node | ✅ |
|
||||
| `motd` | Displays the message of the day or sets it. Example: `motd $New Message Of the day` | ✅ |
|
||||
| `lheard` | Returns the last 5 heard nodes with SNR. Can also use `sitrep` | ✅ |
|
||||
| `history` | Returns the last commands run by user(s) | ✅ |
|
||||
| `sysinfo` | Returns the bot node telemetry info | ✅ |
|
||||
| `cmd` | Returns the list of commands (the help message) | ✅ |
|
||||
|
||||
### Radio Propagation & Weather Forcasting
|
||||
| Command | Description | |
|
||||
|---------|-------------|-------------------
|
||||
| `sun` and `moon` | Return info on rise and set local time | ✅ |
|
||||
| `solar` | Gives an idea of the x-ray flux | |
|
||||
| `ea` and `ealert` | Return FEMA iPAWS/EAS alerts in USA or UK. Headline or expanded details for USA | |
|
||||
| `hfcond` | Returns a table of HF solar conditions | |
|
||||
| `tide` | Returns the local tides (NOAA data source) |
|
||||
| `rlist` | Returns a table of nearby repeaters from RepeaterBook | |
|
||||
| `riverflow` | Return information from NOAA for river flow info. Example: `riverflow modules/settings.py`| |
|
||||
| `solar` | Gives an idea of the x-ray flux | |
|
||||
| `sun` and `moon` | Return info on rise and set local time | ✅ |
|
||||
| `tide` | Returns the local tides (NOAA data source) |
|
||||
| `wx` and `wxc` | Return local weather forecast (wxc is metric value), NOAA or Open Meteo for weather forecasting | |
|
||||
| `wxa` and `wxalert` | Return NOAA alerts. Short title or expanded details | |
|
||||
| `ea` and `ealert` | Return FEMA iPAWS/EAS alerts in USA or UK. Headline or expanded details for USA | |
|
||||
| `riverflow` | Return information from NOAA for river flow info. Example: `riverflow modules/settings.py`| |
|
||||
|
||||
### Bulletin Board & Mail
|
||||
| Command | Description | |
|
||||
@@ -395,22 +399,22 @@ There is no direct support for MQTT in the code, however, reports from Discord a
|
||||
### Data Lookup
|
||||
| Command | Description | |
|
||||
|---------|-------------|-
|
||||
| `wiki:` | Searches Wikipedia and returns the first few sentences of the first result if a match. Example: `wiki: lora radio` |
|
||||
| `askai` and `ask:` | Ask Ollama LLM AI for a response. Example: `askai what temp do I cook chicken` | ✅ |
|
||||
| `messages` | Replays the last messages heard, like Store and Forward | ✅ |
|
||||
| `readnews` | returns the contents of a file (news.txt, by default) via the chunker on air | ✅ |
|
||||
| `satpass` | returns the pass info from API for defined NORAD ID in config or Example: `satpass 25544,33591`| |
|
||||
| `wiki:` | Searches Wikipedia and returns the first few sentences of the first result if a match. Example: `wiki: lora radio` |
|
||||
|
||||
### Games (via DM)
|
||||
| Command | Description | |
|
||||
|---------|-------------|-
|
||||
| `blackjack` | Plays Blackjack (Casino 21) | ✅ |
|
||||
| `dopewars` | Plays the classic drug trader game | ✅ |
|
||||
| `golfsim` | Plays a 9-hole Golf Simulator | ✅ |
|
||||
| `joke` | Tells a joke | ✅ |
|
||||
| `lemonstand` | Plays the classic Lemonade Stand finance game | ✅ |
|
||||
| `dopewars` | Plays the classic drug trader game | ✅ |
|
||||
| `blackjack` | Plays Blackjack (Casino 21) | ✅ |
|
||||
| `videopoker` | Plays basic 5-card hold Video Poker | ✅ |
|
||||
| `mastermind` | Plays the classic code-breaking game | ✅ |
|
||||
| `golfsim` | Plays a 9-hole Golf Simulator | ✅ |
|
||||
| `videopoker` | Plays basic 5-card hold Video Poker | ✅ |
|
||||
|
||||
# Recognition
|
||||
|
||||
@@ -436,6 +440,8 @@ I used ideas and snippets from other responder bots and want to call them out!
|
||||
- **[https://github.com/A-c0rN](A-c0rN)**: Assistance with iPAWS and EAS
|
||||
- **Mike O'Connell/skrrt**: For [eas_alert_parser](etc/eas_alert_parser.py) enhanced by **sheer.cold**
|
||||
- **PiDiBi**: For looking at test functions and other suggestions like wxc, CPU use, and alerting ideas.
|
||||
- **WH6GXZ nurse dude**: For bashing on installer
|
||||
- **Josh**: For more bashing on installer!
|
||||
- **Cisien, bitflip, **Woof**, **propstg**, **Josh** and Hailo1999**: For testing and feature ideas on Discord and GitHub.
|
||||
- **Meshtastic Discord Community**: For tossing out ideas and testing code.
|
||||
|
||||
@@ -443,7 +449,7 @@ I used ideas and snippets from other responder bots and want to call them out!
|
||||
- **Node Backup Management**: [Node Slurper](https://github.com/SpudGunMan/node-slurper)
|
||||
|
||||
### Requirements
|
||||
Python 3.8? or later is needed (dev on latest). The following can be installed with `pip install -r requirements.txt` or using the [install.sh](install.sh) script for venv and automation:
|
||||
Python 3.8? or later is needed (docker on 3.13). The following can be installed with `pip install -r requirements.txt` or using the [install.sh](install.sh) script for venv and automation:
|
||||
|
||||
```sh
|
||||
pip install meshtastic
|
||||
|
||||
@@ -9,7 +9,7 @@ type = serial
|
||||
port = /dev/ttyACM0
|
||||
# port = /dev/ttyUSB0
|
||||
# port = COM1
|
||||
# hostname = 192.168.0.1
|
||||
# hostname = localhost
|
||||
# mac = 00:11:22:33:44:55
|
||||
|
||||
# Additional interface for dual radio support
|
||||
@@ -188,6 +188,8 @@ enable_read_news = False
|
||||
news_file_path = news.txt
|
||||
# only return a single random line from the news file
|
||||
news_random_line = False
|
||||
# enable the use of exernal shell commands
|
||||
enable_runShellCmd = False
|
||||
|
||||
[smtp]
|
||||
# enable or disable the SMTP module
|
||||
@@ -235,7 +237,7 @@ splitDelay = 0.0
|
||||
MESSAGE_CHUNK_SIZE = 160
|
||||
# Request Acknowledgement of message OTA
|
||||
wantAck = False
|
||||
# Max lilmit Buffer for radio testing
|
||||
# Max limit buffer for radio testing. 233 is hard limit 2.5+ firmware
|
||||
maxBuffer = 220
|
||||
|
||||
|
||||
|
||||
148
install.sh
148
install.sh
@@ -11,23 +11,37 @@ printf "\nThis script will try and install the Meshing Around Bot and its depend
|
||||
printf "Installer works best in raspian/debian/ubuntu, if there is a problem, try running the installer again.\n"
|
||||
printf "\nChecking for dependencies...\n"
|
||||
|
||||
# check if running on embedded
|
||||
printf "\nAre You installing into an embedded system? (y/n)"
|
||||
read embedded
|
||||
|
||||
if [ $embedded == "y" ]; then
|
||||
printf "\nDetected embedded skipping dependency installation\n"
|
||||
if [ $program_path != "/opt/meshing-around" ]; then
|
||||
printf "\nIt is suggested to project path to /opt/meshing-around\n"
|
||||
printf "Do you want to move the project to /opt/meshing-around? (y/n)"
|
||||
read move
|
||||
if [ $move == "y" ]; then
|
||||
sudo mv $program_path /opt/meshing-around
|
||||
cd /opt/meshing-around
|
||||
printf "\nProject moved to /opt/meshing-around. re-run the installer\n"
|
||||
exit 0
|
||||
fi
|
||||
# check if we are in /opt/meshing-around
|
||||
if [ $program_path != "/opt/meshing-around" ]; then
|
||||
printf "\nIt is suggested to project path to /opt/meshing-around\n"
|
||||
printf "Do you want to move the project to /opt/meshing-around? (y/n)"
|
||||
read move
|
||||
if [[ $(echo "$move" | grep -iq "^y") ]]; then
|
||||
sudo mv $program_path /opt/meshing-around
|
||||
cd /opt/meshing-around
|
||||
printf "\nProject moved to /opt/meshing-around. re-run the installer\n"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# check write access to program path
|
||||
if [[ ! -w ${program_path} ]]; then
|
||||
printf "\nInstall path not writable, try running the installer with sudo\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# if hostname = femtofox, then we are on embedded
|
||||
if [[ $(hostname) == "femtofox" ]]; then
|
||||
printf "\nDetected femtofox embedded system\n"
|
||||
embedded="y"
|
||||
else
|
||||
# check if running on embedded
|
||||
printf "\nAre You installing into an embedded system like a luckfox? (y/n)"
|
||||
read embedded
|
||||
fi
|
||||
|
||||
if [[ $(echo "${embedded}" | grep -i "^y") ]]; then
|
||||
printf "\nDetected embedded skipping dependency installation\n"
|
||||
else
|
||||
# Check and install dependencies
|
||||
if ! command -v python3 &> /dev/null
|
||||
@@ -67,7 +81,7 @@ cp etc/mesh_bot.tmp etc/mesh_bot.service
|
||||
cp etc/mesh_bot_reporting.tmp etc/mesh_bot_reporting.service
|
||||
|
||||
# generate config file, check if it exists
|
||||
if [ -f config.ini ]; then
|
||||
if [[ -f config.ini ]]; then
|
||||
printf "\nConfig file already exists, moving to backup config.old\n"
|
||||
mv config.ini config.old
|
||||
fi
|
||||
@@ -76,13 +90,13 @@ cp config.template config.ini
|
||||
printf "\nConfig files generated!\n"
|
||||
|
||||
# check if running on embedded
|
||||
if [ $embedded == "y" ]; then
|
||||
if [[ $(echo "${embedded}" | grep -iq "^y") ]]; then
|
||||
printf "\nDetected embedded skipping venv\n"
|
||||
else
|
||||
printf "\nDo you want to install the bot in a python virtual environment? (y/n)"
|
||||
printf "\nRecomended install is in a python virtual environment, do you want to use venv? (y/n)"
|
||||
read venv
|
||||
|
||||
if [ $venv == "y" ]; then
|
||||
if [[ $(echo "${venv}" | grep -i "^y") ]]; then
|
||||
# set virtual environment
|
||||
if ! python3 -m venv --help &> /dev/null; then
|
||||
printf "Python3/venv error, please install python3-venv with your OS\n"
|
||||
@@ -91,7 +105,7 @@ else
|
||||
echo "The Following could be messy, or take some time on slower devices."
|
||||
echo "Creating virtual environment..."
|
||||
#check if python3 has venv module
|
||||
if [ -f venv/bin/activate ]; then
|
||||
if [[ -f venv/bin/activate ]]; then
|
||||
printf "\nFound virtual environment for python\n"
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
@@ -103,7 +117,7 @@ else
|
||||
python3 -m venv venv
|
||||
|
||||
# double check for python3-venv
|
||||
if [ -f venv/bin/activate ]; then
|
||||
if [[ -f venv/bin/activate ]]; then
|
||||
printf "\nFound virtual environment for python\n"
|
||||
source venv/bin/activate
|
||||
else
|
||||
@@ -119,15 +133,15 @@ else
|
||||
replace="s|python3 pong_bot.py|/usr/bin/bash launch.sh pong|g"
|
||||
sed -i "$replace" etc/pong_bot.service
|
||||
|
||||
# install dependencies
|
||||
# install dependencies to venv
|
||||
pip install -U -r requirements.txt
|
||||
fi
|
||||
else
|
||||
printf "\nSkipping virtual environment...\n"
|
||||
# install dependencies
|
||||
# install dependencies to system
|
||||
printf "Are you on Raspberry Pi(debian/ubuntu)?\nshould we add --break-system-packages to the pip install command? (y/n)"
|
||||
read rpi
|
||||
if [ $rpi == "y" ]; then
|
||||
if [[ $(echo "${rpi}" | grep -i "^y") ]]; then
|
||||
pip install -U -r requirements.txt --break-system-packages
|
||||
else
|
||||
pip install -U -r requirements.txt
|
||||
@@ -137,6 +151,7 @@ fi
|
||||
|
||||
printf "\n\n"
|
||||
echo "Which bot do you want to install as a service? Pong Mesh or None? (pong/mesh/n)"
|
||||
echo "Pong bot is a simple bot for network testing, Mesh bot is a more complex bot more suited for meshing around"
|
||||
read bot
|
||||
|
||||
# set the correct path in the service file
|
||||
@@ -145,7 +160,32 @@ sed -i $replace etc/pong_bot.service
|
||||
sed -i $replace etc/mesh_bot.service
|
||||
sed -i $replace etc/mesh_bot_reporting.service
|
||||
# set the correct user in the service file?
|
||||
whoami=$(whoami)
|
||||
|
||||
#ask if we should add a user for the bot
|
||||
if [[ $(echo "${embedded}" | grep -i "^y") ]]; then
|
||||
printf "\nDo you want to add a local user (meshbot) no login, for the bot? (y/n)"
|
||||
read meshbotservice
|
||||
else
|
||||
meshbotservice="n"
|
||||
fi
|
||||
|
||||
if [[ $(echo "${meshbotservice}" | grep -i "^y") ]] || [[ $(echo "${embedded}" | grep -i "^y") ]]; then
|
||||
sudo useradd -M meshbot
|
||||
sudo usermod -L meshbot
|
||||
whoami="meshbot"
|
||||
echo "Added user meshbot with no home directory"
|
||||
sudo usermod -a -G dialout $whoami
|
||||
sudo usermod -a -G tty $whoami
|
||||
sudo usermod -a -G bluetooth $whoami
|
||||
echo "Added meshbot to dialout, tty, and bluetooth groups"
|
||||
|
||||
sudo chown -R $whoami:$whoami $program_path/logs
|
||||
sudo chown -R $whoami:$whoami $program_path/data
|
||||
echo "Permissions set for meshbot on logs and data directories"
|
||||
else
|
||||
whoami=$(whoami)
|
||||
fi
|
||||
# set the correct user in the service file
|
||||
replace="s|User=pi|User=$whoami|g"
|
||||
sed -i $replace etc/pong_bot.service
|
||||
sed -i $replace etc/mesh_bot.service
|
||||
@@ -154,64 +194,60 @@ replace="s|Group=pi|Group=$whoami|g"
|
||||
sed -i $replace etc/pong_bot.service
|
||||
sed -i $replace etc/mesh_bot.service
|
||||
sed -i $replace etc/mesh_bot_reporting.service
|
||||
sudo systemctl daemon-reload
|
||||
printf "\n service files updated\n"
|
||||
|
||||
if [ $bot == "pong" ]; then
|
||||
echo "useradd -M meshbot"
|
||||
echo "usermod -L meshbot"
|
||||
echo "Added user meshbot with no home directory"
|
||||
if [[ $(echo "${bot}" | grep -i "^p") ]]; then
|
||||
# install service for pong bot
|
||||
sudo cp etc/pong_bot.service /etc/systemd/system/
|
||||
sudo systemctl enable pong_bot.service
|
||||
sudo systemctl daemon-reload
|
||||
echo "to start pong bot service: systemctl start pong_bot"
|
||||
fi
|
||||
|
||||
if [ $bot == "mesh" ]; then
|
||||
echo "useradd -M meshbot"
|
||||
echo "usermod -L meshbot"
|
||||
echo "Added user meshbot with no home directory"
|
||||
if [[ $(echo "${bot}" | grep -i "^m") ]]; then
|
||||
# install service for mesh bot
|
||||
sudo cp etc/mesh_bot.service /etc/systemd/system/
|
||||
sudo systemctl enable mesh_bot.service
|
||||
sudo systemctl daemon-reload
|
||||
echo "to start mesh bot service: systemctl start mesh_bot"
|
||||
fi
|
||||
|
||||
# check if running on embedded
|
||||
if [ $embedded == "n" ]; then
|
||||
# check if running on embedded for final steps
|
||||
if [[ $(echo "${embedded}" | grep -i "^n") ]]; then
|
||||
# ask if emoji font should be installed for linux
|
||||
printf "\nDo you want to install the emoji font for debian/ubuntu linux? (y/n)"
|
||||
read emoji
|
||||
if [ $emoji == "y" ]; then
|
||||
if [[ $(echo "${emoji}" | grep -i "^y") ]]; then
|
||||
sudo apt-get install -y fonts-noto-color-emoji
|
||||
echo "Emoji font installed!, reboot to load the font"
|
||||
fi
|
||||
|
||||
|
||||
printf "\nOptionally if you want to install the multi gig LLM Ollama compnents we will execute the following commands\n"
|
||||
printf "\ncurl -fsSL https://ollama.com/install.sh | sh\n"
|
||||
|
||||
printf "ollama pull gemma2:2b\n"
|
||||
printf "Total download is multi GB, recomend pi5/8GB or better for this\n"
|
||||
# ask if the user wants to install the LLM Ollama components
|
||||
printf "\nDo you want to install the LLM Ollama components? (y/n)"
|
||||
read ollama
|
||||
if [ $ollama == "y" ]; then
|
||||
if [[ $(echo "${ollama}" | grep -i "^y") ]]; then
|
||||
curl -fsSL https://ollama.com/install.sh | sh
|
||||
|
||||
# ask if want to install gemma2:2b
|
||||
printf "\n Ollama install done now we can install the Gemma2:2b components, multi GB download\n"
|
||||
printf "\n Ollama install done now we can install the Gemma2:2b components\n"
|
||||
echo "Do you want to install the Gemma2:2b components? (y/n)"
|
||||
read gemma
|
||||
if [ $gemma == "y" ]; then
|
||||
if [[ $(echo "${gemma}" | grep -i "^y") ]]; then
|
||||
ollama pull gemma2:2b
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if [ $venv == "y" ]; then
|
||||
printf "\nFor running in virtual, launch bot with './launch.sh mesh' in path $program_path\n"
|
||||
if [[ $(echo "${venv}" | grep -i "^y") ]]; then
|
||||
printf "\nFor running on venv, virtual launch bot with './launch.sh mesh' in path $program_path\n"
|
||||
fi
|
||||
|
||||
printf "\nGood time to reboot? (y/n)"
|
||||
read reboot
|
||||
if [ $reboot == "y" ]; then
|
||||
if [[ $(echo "${reboot}" | grep -i "^y") ]]; then
|
||||
sudo reboot
|
||||
fi
|
||||
else
|
||||
@@ -220,15 +256,25 @@ else
|
||||
replace="s|type = serial|type = tcp|g"
|
||||
sed -i "$replace" config.ini
|
||||
# replace "# hostname = 192.168.0.1" with "hostname = localhost" in config.ini
|
||||
replace="s|# hostname = 192.168.0.1|hostname = localhost|g"
|
||||
replace="s|# hostname = localhost|hostname = localhost|g"
|
||||
sed -i "$replace" config.ini
|
||||
printf "\nConfig file updated for embedded\n"
|
||||
|
||||
# Set up the meshing around service
|
||||
#sudo cp /opt/meshing-around/meshing-around.service /etc/systemd/system/meshing-around.service
|
||||
#sudo systemctl enable meshing-around.service
|
||||
printf "To install the meshing around service and keep notes, copy and paste the following commands:\n\n"
|
||||
printf "sudo cp /opt/meshing-around/meshing-around.service /etc/systemd/system/meshing-around.service\n"
|
||||
printf "sudo systemctl daemon-reload\n"
|
||||
printf "sudo systemctl enable meshing-around.service\n"
|
||||
printf "sudo systemctl start meshing-around.service\n"
|
||||
printf "sudo systemctl status meshing-around.service\n\n"
|
||||
printf "To see logs and stop the service:\n"
|
||||
printf "sudo journalctl -u meshing-around.service\n"
|
||||
printf "sudo systemctl stop meshing-around.service\n"
|
||||
printf "sudo systemctl disable meshing-around.service\n"
|
||||
fi
|
||||
|
||||
printf "\nInstallation complete!\n"
|
||||
exit 0
|
||||
|
||||
# after install shenannigans
|
||||
# add 'bee = True' to config.ini General section. You will likley want to clean the txt up a bit
|
||||
# wget https://courses.cs.washington.edu/courses/cse163/20wi/files/lectures/L04/bee-movie.txt -O bee.txt
|
||||
|
||||
17
mesh_bot.py
17
mesh_bot.py
@@ -5,7 +5,7 @@
|
||||
import asyncio
|
||||
import time # for sleep, get some when you can :)
|
||||
import random
|
||||
from pubsub import pub # pip install pubsub
|
||||
from pubsub import pub # pip install pubsub, use launch.sh for venv
|
||||
from modules.log import *
|
||||
from modules.system import *
|
||||
|
||||
@@ -87,6 +87,7 @@ def auto_response(message, snr, rssi, hop, pkiStatus, message_from_id, channel_n
|
||||
"wxc": lambda: handle_wxc(message_from_id, deviceID, 'wxc'),
|
||||
"📍": lambda: handle_whoami(message_from_id, deviceID, hop, snr, rssi, pkiStatus),
|
||||
"🔔": lambda: handle_alertBell(message_from_id, deviceID, message),
|
||||
"🐝": lambda: read_file("bee.txt", True),
|
||||
# any value from system.py:trap_list_emergency will trigger the emergency function
|
||||
"112": lambda: handle_emergency(message_from_id, deviceID, message),
|
||||
"911": lambda: handle_emergency(message_from_id, deviceID, message),
|
||||
@@ -768,7 +769,11 @@ def sysinfo(message, message_from_id, deviceID):
|
||||
if "?" in message:
|
||||
return "sysinfo command returns system information."
|
||||
else:
|
||||
return get_sysinfo(message_from_id, deviceID)
|
||||
if enable_runShellCmd and file_monitor_enabled:
|
||||
shellData = call_external_script(None, "sysEnv.sh").rstrip()
|
||||
return get_sysinfo(message_from_id, deviceID) + "\n" + shellData
|
||||
else:
|
||||
return get_sysinfo(message_from_id, deviceID)
|
||||
|
||||
def handle_lheard(message, nodeid, deviceID, isDM):
|
||||
if "?" in message and isDM:
|
||||
@@ -1274,8 +1279,12 @@ async def start_rx():
|
||||
logger.debug(f"System: Radio Detection Enabled using rigctld at {rigControlServerAddress} brodcasting to channels: {sigWatchBroadcastCh} for {get_freq_common_name(get_hamlib('f'))}")
|
||||
if file_monitor_enabled:
|
||||
logger.debug(f"System: File Monitor Enabled for {file_monitor_file_path}, broadcasting to channels: {file_monitor_broadcastCh}")
|
||||
if read_news_enabled:
|
||||
logger.debug(f"System: File Monitor News Reader Enabled for {news_file_path}")
|
||||
if enable_runShellCmd:
|
||||
logger.debug(f"System: Shell Command monitor enabled")
|
||||
if read_news_enabled:
|
||||
logger.debug(f"System: File Monitor News Reader Enabled for {news_file_path}")
|
||||
if bee_enabled:
|
||||
logger.debug(f"System: File Monitor Bee Monitor Enabled for bee.txt")
|
||||
if wxAlertBroadcastEnabled:
|
||||
logger.debug(f"System: Weather Alert Broadcast Enabled on channels {wxAlertBroadcastChannel}")
|
||||
if emergencyAlertBrodcastEnabled:
|
||||
|
||||
@@ -9,7 +9,12 @@ import os
|
||||
trap_list_filemon = ("readnews",)
|
||||
|
||||
def read_file(file_monitor_file_path, random_line_only=False):
|
||||
|
||||
try:
|
||||
if not os.path.exists(file_monitor_file_path):
|
||||
logger.warning(f"FileMon: File not found: {file_monitor_file_path}")
|
||||
if file_monitor_file_path == "bee.txt":
|
||||
return "🐝buzz 💐buzz buzz🍯"
|
||||
if random_line_only:
|
||||
# read a random line from the file
|
||||
with open(file_monitor_file_path, 'r') as f:
|
||||
@@ -56,4 +61,24 @@ async def watch_file():
|
||||
content = content.replace('\n', ' ').replace('\r', '').strip()
|
||||
if content:
|
||||
return content
|
||||
await asyncio.sleep(1) # Check every
|
||||
await asyncio.sleep(1) # Check every
|
||||
|
||||
def call_external_script(message, script="runShell.sh"):
|
||||
try:
|
||||
# Debugging: Print the current working directory and resolved script path
|
||||
current_working_directory = os.getcwd()
|
||||
script_path = os.path.join(current_working_directory, script)
|
||||
|
||||
if not os.path.exists(script_path):
|
||||
# try the raw script name
|
||||
script_path = script
|
||||
if not os.path.exists(script_path):
|
||||
logger.warning(f"FileMon: Script not found: {script_path}")
|
||||
return "sorry I can't do that"
|
||||
|
||||
output = os.popen(f"bash {script_path} {message}").read()
|
||||
return output
|
||||
except Exception as e:
|
||||
logger.warning(f"FileMon: Error calling external script: {e}")
|
||||
return None
|
||||
|
||||
@@ -542,9 +542,9 @@ def getIpawsAlert(lat=0, lon=0, shortAlerts = False):
|
||||
'geocode_value': geocode_value,
|
||||
'description': description
|
||||
})
|
||||
else:
|
||||
# these are discarded some day but logged for debugging currently
|
||||
logger.debug(f"Debug iPAWS: Type:{alertType} Code:{alertCode} Desc:{areaDesc} GeoType:{geocode_type} GeoVal:{geocode_value}, Headline:{headline}")
|
||||
# else:
|
||||
# # these are discarded some day but logged for debugging currently
|
||||
# logger.debug(f"Debug iPAWS: Type:{alertType} Code:{alertCode} Desc:{areaDesc} GeoType:{geocode_type} GeoVal:{geocode_value}, Headline:{headline}")
|
||||
|
||||
# return the numWxAlerts of alerts
|
||||
if len(alerts) > 0:
|
||||
|
||||
@@ -130,6 +130,7 @@ try:
|
||||
whoami_enabled = config['general'].getboolean('whoami', True)
|
||||
dad_jokes_enabled = config['general'].getboolean('DadJokes', False)
|
||||
dad_jokes_emojiJokes = config['general'].getboolean('DadJokesEmoji', False)
|
||||
bee_enabled = config['general'].getboolean('bee', False) # 🐝 off by default undocumented
|
||||
solar_conditions_enabled = config['general'].getboolean('spaceWeather', True)
|
||||
wikipedia_enabled = config['general'].getboolean('wikipedia', False)
|
||||
llm_enabled = config['general'].getboolean('ollama', False) # https://ollama.com
|
||||
@@ -221,6 +222,7 @@ try:
|
||||
read_news_enabled = config['fileMon'].getboolean('enable_read_news', False) # default disabled
|
||||
news_file_path = config['fileMon'].get('news_file_path', 'news.txt') # default news.txt
|
||||
news_random_line_only = config['fileMon'].getboolean('news_random_line', False) # default False
|
||||
enable_runShellCmd = config['fileMon'].getboolean('enable_runShellCmd', False) # default False
|
||||
|
||||
# games
|
||||
game_hop_limit = config['messagingSettings'].getint('game_hop_limit', 5) # default 3 hops
|
||||
|
||||
@@ -12,6 +12,7 @@ import io # for suppressing output on watchdog
|
||||
from modules.log import *
|
||||
|
||||
# Global Variables
|
||||
debugMetadata = False # packet debug for non text messages
|
||||
trap_list = ("cmd","cmd?") # default trap list
|
||||
help_message = "Bot CMD?:"
|
||||
asyncLoop = asyncio.new_event_loop()
|
||||
@@ -75,7 +76,7 @@ if location_enabled:
|
||||
trap_list = trap_list + trap_list_location # items tide, whereami, wxc, wx
|
||||
help_message = help_message + ", whereami, wx, wxc, rlist"
|
||||
if enableGBalerts:
|
||||
from modules.locationdata_eu import * # from the spudgunman/meshing-around repo
|
||||
from modules.globalalert import * # from the spudgunman/meshing-around repo
|
||||
trap_list = trap_list + trap_list_location_eu
|
||||
#help_message = help_message + ", ukalert, ukwx, ukflood"
|
||||
|
||||
@@ -195,6 +196,9 @@ if file_monitor_enabled or read_news_enabled:
|
||||
if read_news_enabled:
|
||||
trap_list = trap_list + trap_list_filemon # items readnews
|
||||
help_message = help_message + ", readnews"
|
||||
# Bee Configuration uses file monitor module
|
||||
if bee_enabled:
|
||||
trap_list = trap_list + ("🐝",)
|
||||
|
||||
# clean up the help message
|
||||
help_message = help_message.split(", ")
|
||||
@@ -666,6 +670,9 @@ def handleMultiPing(nodeID=0, deviceID=1):
|
||||
|
||||
|
||||
def handleAlertBroadcast(deviceID=1):
|
||||
alertUk = NO_ALERTS
|
||||
alertFema = NO_ALERTS
|
||||
wxAlert = NO_ALERTS
|
||||
# only allow API call every 20 minutes
|
||||
# the watchdog will call this function 3 times, seeing possible throttling on the API
|
||||
clock = datetime.now()
|
||||
@@ -675,13 +682,15 @@ def handleAlertBroadcast(deviceID=1):
|
||||
return False
|
||||
|
||||
# check for alerts
|
||||
alertWx = alertBrodcastNOAA()
|
||||
alertFema = getIpawsAlert(latitudeValue,longitudeValue, shortAlerts=True)
|
||||
if wxAlertBroadcastEnabled:
|
||||
alertWx = alertBrodcastNOAA()
|
||||
|
||||
if enableGBalerts:
|
||||
alertUk = get_govUK_alerts()
|
||||
else:
|
||||
alertUk = NO_ALERTS
|
||||
if emergencyAlertBrodcastEnabled:
|
||||
if enableGBalerts:
|
||||
alertUk = get_govUK_alerts()
|
||||
else:
|
||||
# default USA alerts
|
||||
alertFema = getIpawsAlert(latitudeValue,longitudeValue, shortAlerts=True)
|
||||
|
||||
# format alert
|
||||
if alertWx:
|
||||
@@ -693,7 +702,7 @@ def handleAlertBroadcast(deviceID=1):
|
||||
ukAlert = alertUk
|
||||
|
||||
if emergencyAlertBrodcastEnabled:
|
||||
if NO_ALERTS not in femaAlert:
|
||||
if NO_ALERTS not in femaAlert and ERROR_FETCHING_DATA not in femaAlert:
|
||||
if isinstance(emergencyAlertBroadcastCh, list):
|
||||
for channel in emergencyAlertBroadcastCh:
|
||||
send_message(femaAlert, int(channel), 0, deviceID)
|
||||
@@ -855,90 +864,92 @@ def displayNodeTelemetry(nodeID=0, rxNode=0, userRequested=False):
|
||||
|
||||
positionMetadata = {}
|
||||
def consumeMetadata(packet, rxNode=0):
|
||||
# keep records of recent telemetry data
|
||||
debugMetadata = False
|
||||
packet_type = ''
|
||||
if packet.get('decoded'):
|
||||
packet_type = packet['decoded']['portnum']
|
||||
nodeID = packet['from']
|
||||
try:
|
||||
# keep records of recent telemetry data
|
||||
packet_type = ''
|
||||
if packet.get('decoded'):
|
||||
packet_type = packet['decoded']['portnum']
|
||||
nodeID = packet['from']
|
||||
|
||||
# TELEMETRY packets
|
||||
if packet_type == 'TELEMETRY_APP':
|
||||
#if debugMetadata: print(f"DEBUG TELEMETRY_APP: {packet}\n\n")
|
||||
# get the telemetry data
|
||||
telemetry_packet = packet['decoded']['telemetry']
|
||||
if telemetry_packet.get('deviceMetrics'):
|
||||
deviceMetrics = telemetry_packet['deviceMetrics']
|
||||
if telemetry_packet.get('localStats'):
|
||||
localStats = telemetry_packet['localStats']
|
||||
# Check if 'numPacketsTx' and 'numPacketsRx' exist and are not zero
|
||||
if localStats.get('numPacketsTx') is not None and localStats.get('numPacketsRx') is not None and localStats['numPacketsTx'] != 0:
|
||||
# Assign the values to the telemetry dictionary
|
||||
keys = [
|
||||
'numPacketsTx', 'numPacketsRx', 'numOnlineNodes',
|
||||
'numOfflineNodes', 'numPacketsTxErr', 'numPacketsRxErr', 'numTotalNodes']
|
||||
|
||||
# TELEMETRY packets
|
||||
if packet_type == 'TELEMETRY_APP':
|
||||
if debugMetadata: print(f"DEBUG TELEMETRY_APP: {packet}\n\n")
|
||||
# get the telemetry data
|
||||
telemetry_packet = packet['decoded']['telemetry']
|
||||
if telemetry_packet.get('deviceMetrics'):
|
||||
deviceMetrics = telemetry_packet['deviceMetrics']
|
||||
if telemetry_packet.get('localStats'):
|
||||
localStats = telemetry_packet['localStats']
|
||||
# Check if 'numPacketsTx' and 'numPacketsRx' exist and are not zero
|
||||
if localStats.get('numPacketsTx') is not None and localStats.get('numPacketsRx') is not None and localStats['numPacketsTx'] != 0:
|
||||
# Assign the values to the telemetry dictionary
|
||||
keys = [
|
||||
'numPacketsTx', 'numPacketsRx', 'numOnlineNodes',
|
||||
'numOfflineNodes', 'numPacketsTxErr', 'numPacketsRxErr', 'numTotalNodes']
|
||||
|
||||
for key in keys:
|
||||
if localStats.get(key) is not None:
|
||||
telemetryData[rxNode][key] = localStats.get(key)
|
||||
|
||||
# POSITION_APP packets
|
||||
if packet_type == 'POSITION_APP':
|
||||
if debugMetadata: print(f"DEBUG POSITION_APP: {packet}\n\n")
|
||||
# get the position data
|
||||
keys = ['altitude', 'groundSpeed', 'precisionBits']
|
||||
position_data = packet['decoded']['position']
|
||||
try:
|
||||
if nodeID not in positionMetadata:
|
||||
positionMetadata[nodeID] = {}
|
||||
|
||||
for key in keys:
|
||||
if localStats.get(key) is not None:
|
||||
telemetryData[rxNode][key] = localStats.get(key)
|
||||
|
||||
# POSITION_APP packets
|
||||
if packet_type == 'POSITION_APP':
|
||||
if debugMetadata: print(f"DEBUG POSITION_APP: {packet}\n\n")
|
||||
# get the position data
|
||||
keys = ['altitude', 'groundSpeed', 'precisionBits']
|
||||
position_data = packet['decoded']['position']
|
||||
try:
|
||||
if nodeID not in positionMetadata:
|
||||
positionMetadata[nodeID] = {}
|
||||
|
||||
for key in keys:
|
||||
positionMetadata[nodeID][key] = position_data.get(key, 0)
|
||||
|
||||
# Keep the positionMetadata dictionary at 5 records
|
||||
if len(positionMetadata) > 20:
|
||||
# Remove the oldest entry
|
||||
oldest_nodeID = next(iter(positionMetadata))
|
||||
del positionMetadata[oldest_nodeID]
|
||||
except Exception as e:
|
||||
logger.debug(f"System: POSITION_APP decode error: {e} packet {packet}")
|
||||
positionMetadata[nodeID][key] = position_data.get(key, 0)
|
||||
|
||||
# Keep the positionMetadata dictionary at 5 records
|
||||
if len(positionMetadata) > 20:
|
||||
# Remove the oldest entry
|
||||
oldest_nodeID = next(iter(positionMetadata))
|
||||
del positionMetadata[oldest_nodeID]
|
||||
except Exception as e:
|
||||
logger.debug(f"System: POSITION_APP decode error: {e} packet {packet}")
|
||||
|
||||
# WAYPOINT_APP packets
|
||||
if packet_type == 'WAYPOINT_APP':
|
||||
if debugMetadata: print(f"DEBUG WAYPOINT_APP: {packet['decoded']['waypoint']}\n\n")
|
||||
# get the waypoint data
|
||||
waypoint_data = packet['decoded']['waypoint']
|
||||
keys = ['latitude', 'longitude',]
|
||||
# WAYPOINT_APP packets
|
||||
if packet_type == 'WAYPOINT_APP':
|
||||
if debugMetadata: print(f"DEBUG WAYPOINT_APP: {packet['decoded']['waypoint']}\n\n")
|
||||
# get the waypoint data
|
||||
waypoint_data = packet['decoded']
|
||||
|
||||
# NEIGHBORINFO_APP
|
||||
if packet_type == 'NEIGHBORINFO_APP':
|
||||
if debugMetadata: print(f"DEBUG NEIGHBORINFO_APP: {packet}\n\n")
|
||||
# get the neighbor info data
|
||||
neighbor_data = packet['decoded']['neighborInfo']
|
||||
|
||||
# TRACEROUTE_APP
|
||||
if packet_type == 'TRACEROUTE_APP':
|
||||
if debugMetadata: print(f"DEBUG TRACEROUTE_APP: {packet}\n\n")
|
||||
# get the traceroute data
|
||||
traceroute_data = packet['decoded']['traceroute']
|
||||
# NEIGHBORINFO_APP
|
||||
if packet_type == 'NEIGHBORINFO_APP':
|
||||
if debugMetadata: print(f"DEBUG NEIGHBORINFO_APP: {packet}\n\n")
|
||||
# get the neighbor info data
|
||||
neighbor_data = packet['decoded']
|
||||
|
||||
# TRACEROUTE_APP
|
||||
if packet_type == 'TRACEROUTE_APP':
|
||||
if debugMetadata: print(f"DEBUG TRACEROUTE_APP: {packet}\n\n")
|
||||
# get the traceroute data
|
||||
traceroute_data = packet['decoded']
|
||||
|
||||
# DETECTION_SENSOR_APP
|
||||
if packet_type == 'DETECTION_SENSOR_APP':
|
||||
if debugMetadata: print(f"DEBUG DETECTION_SENSOR_APP: {packet}\n\n")
|
||||
# get the detection sensor data
|
||||
detection_data = packet['decoded']['detectionSensor']
|
||||
# DETECTION_SENSOR_APP
|
||||
if packet_type == 'DETECTION_SENSOR_APP':
|
||||
if debugMetadata: print(f"DEBUG DETECTION_SENSOR_APP: {packet}\n\n")
|
||||
# get the detection sensor data
|
||||
detection_data = packet['decoded']
|
||||
|
||||
# PAXCOUNTER_APP
|
||||
if packet_type == 'PAXCOUNTER_APP':
|
||||
if debugMetadata: print(f"DEBUG PAXCOUNTER_APP: {packet}\n\n")
|
||||
# get the paxcounter data
|
||||
paxcounter_data = packet['decoded']['paxcounter']
|
||||
# PAXCOUNTER_APP
|
||||
if packet_type == 'PAXCOUNTER_APP':
|
||||
if debugMetadata: print(f"DEBUG PAXCOUNTER_APP: {packet}\n\n")
|
||||
# get the paxcounter data
|
||||
paxcounter_data = packet['decoded']
|
||||
|
||||
# REMOTE_HARDWARE_APP
|
||||
if packet_type == 'REMOTE_HARDWARE_APP':
|
||||
if debugMetadata: print(f"DEBUG REMOTE_HARDWARE_APP: {packet}\n\n")
|
||||
# get the remote hardware data
|
||||
remote_hardware_data = packet['decoded']['remoteHardware']
|
||||
# REMOTE_HARDWARE_APP
|
||||
if packet_type == 'REMOTE_HARDWARE_APP':
|
||||
if debugMetadata: print(f"DEBUG REMOTE_HARDWARE_APP: {packet}\n\n")
|
||||
# get the remote hardware data
|
||||
remote_hardware_data = packet['decoded']
|
||||
except KeyError as e:
|
||||
logger.critical(f"System: Error consuming metadata: {e} Device:{rxNode}")
|
||||
logger.debug(f"System: Error Packet = {packet}")
|
||||
|
||||
def get_sysinfo(nodeID=0, deviceID=1):
|
||||
# Get the system telemetry data for return on the sysinfo command
|
||||
@@ -1162,7 +1173,7 @@ async def watchdog():
|
||||
# Alert Broadcast
|
||||
if wxAlertBroadcastEnabled or emergencyAlertBrodcastEnabled:
|
||||
# weather alerts
|
||||
handleAlertBroadcast(1)
|
||||
handleAlertBroadcast(2)
|
||||
|
||||
# Telemetry data
|
||||
int2Data = displayNodeTelemetry(0, 2)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import asyncio
|
||||
import time # for sleep, get some when you can :)
|
||||
from pubsub import pub # pip install pubsub
|
||||
from pubsub import pub # pip install pubsub, use launch.sh for venv
|
||||
from modules.log import *
|
||||
from modules.system import *
|
||||
|
||||
|
||||
7
runShell.sh
Normal file
7
runShell.sh
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
# meshing-around demo script for shell scripting
|
||||
# runShell.sh
|
||||
cd "$(dirname "$0")"
|
||||
program_path=$(pwd)
|
||||
|
||||
printf "Running meshing-around demo script for shell scripting\n"
|
||||
30
sysEnv.sh
Normal file
30
sysEnv.sh
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
# meshing-around shell script for sysinfo
|
||||
# runShell.sh
|
||||
cd "$(dirname "$0")"
|
||||
program_path=$(pwd)
|
||||
|
||||
# get basic telemetry data. Free space, CPU, RAM, and temperature for a raspberry pi
|
||||
free_space=$(df -h | grep ' /$' | awk '{print $4}')
|
||||
cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
|
||||
ram_usage=$(free | grep Mem | awk '{print $3/$2 * 100.0}')
|
||||
ram_free=$(echo "scale=2; 100 - $ram_usage" | bc)
|
||||
|
||||
# if command vcgencmd is found, part of raspberrypi tools, use it to get temperature
|
||||
if command -v vcgencmd &> /dev/null
|
||||
then
|
||||
# get temperature
|
||||
temp=$(vcgencmd measure_temp | sed "s/temp=//" | sed "s/'C//")
|
||||
# temp in fahrenheit
|
||||
tempf=$(echo "scale=2; $temp * 9 / 5 + 32" | bc)
|
||||
else
|
||||
# get temperature from thermal zone
|
||||
temp=$(paste <(cat /sys/class/thermal/thermal_zone*/type) <(cat /sys/class/thermal/thermal_zone*/temp) | grep "temp" | awk '{print $2/1000}' | awk '{s+=$1} END {print s/NR}')
|
||||
tempf=$(echo "scale=2; $temp * 9 / 5 + 32" | bc)
|
||||
fi
|
||||
|
||||
# print telemetry data
|
||||
printf "Disk:%s" "$free_space"
|
||||
printf " RAM:%.2f%%" "$ram_usage"
|
||||
printf " CPU:%.1f%%" "$cpu_usage"
|
||||
printf " CPU-T:%.1f°C (%.1f°F)" "$temp" "$tempf"
|
||||
Reference in New Issue
Block a user