Compare commits

..

164 Commits
v1.2 ... v1.3.3

Author SHA1 Message Date
SpudGunMan
d425298cd9 Update dopewar.py 2024-09-28 12:17:16 -07:00
SpudGunMan
786815d073 Update dopewar.py 2024-09-28 12:04:17 -07:00
SpudGunMan
54cad92a3f enhance 💊 game display 2024-09-28 12:03:08 -07:00
SpudGunMan
54e21f4644 Update mesh_bot.py 2024-09-28 00:53:19 -07:00
SpudGunMan
3c76f177cd Update simulator.py 2024-09-28 00:46:47 -07:00
SpudGunMan
aa05c62d94 fix🍋hs 2024-09-28 00:45:57 -07:00
SpudGunMan
3f16158e27 Update mesh_bot.py 2024-09-28 00:28:59 -07:00
SpudGunMan
6f2824512d highscoreEnhance 2024-09-28 00:27:45 -07:00
SpudGunMan
723b67f886 🥔 2024-09-28 00:14:27 -07:00
SpudGunMan
008d55e63b Update mesh_bot.py 2024-09-28 00:12:33 -07:00
SpudGunMan
79885454ab fixLongStandingIssues
fix long time bugs of 21 and the suggestions
2024-09-27 23:47:14 -07:00
SpudGunMan
ba21723bdc fix BlackJackwin! 2024-09-27 23:38:40 -07:00
SpudGunMan
c36c4918a8 Update mesh_bot.py 2024-09-27 22:33:07 -07:00
SpudGunMan
853147518d space 2024-09-27 22:32:46 -07:00
SpudGunMan
2f19d86c95 💩
: get it
2024-09-27 22:17:07 -07:00
SpudGunMan
39bdabffcb Update blackjack.py 2024-09-27 21:57:40 -07:00
SpudGunMan
a7bdaedfe1 Update blackjack.py 2024-09-27 21:57:22 -07:00
SpudGunMan
1c6106081f Weight2Wait
add weight to the wait for responses. as the comment says this is a specific use case for the Q: blah blah A: 2. I am seeing a hang up this is to help keep delivery high.
2024-09-27 21:48:13 -07:00
SpudGunMan
8ab6cded2e 🥝 2024-09-27 21:14:06 -07:00
SpudGunMan
ff63bb959a Update mesh_bot.py 2024-09-27 20:55:50 -07:00
SpudGunMan
6c79bb1ff0 Update mesh_bot.py 2024-09-27 20:50:36 -07:00
SpudGunMan
ce73336c0c Update mesh_bot.py 2024-09-27 20:49:05 -07:00
SpudGunMan
248977c5b5 enhance
* replay hand with H or R
2024-09-27 18:06:11 -07:00
SpudGunMan
77a6e63210 howRandom 2024-09-27 17:39:55 -07:00
SpudGunMan
6f6fb35177 IgnoreDefaultChannel
ability to fully ignore the default channel if wanted, default is false
2024-09-27 17:37:34 -07:00
SpudGunMan
9db565cb4f changeLogPath
tidy up this mess
2024-09-27 17:18:35 -07:00
SpudGunMan
2a254a7fab fixNewTable.pkl 2024-09-27 01:06:15 -07:00
SpudGunMan
15e76ab029 fixCasinoGamesForGood? 2024-09-27 00:57:57 -07:00
SpudGunMan
66b95cdaa0 casinoHighScores
I got a really good score its a shame it was wasted
2024-09-27 00:25:17 -07:00
SpudGunMan
32ea93cb88 Update mesh_bot.py 2024-09-26 22:11:42 -07:00
SpudGunMan
22a2a64861 Update bbstools.py 2024-09-26 21:08:29 -07:00
SpudGunMan
d841fdf02c bbsinfo 2024-09-26 21:03:57 -07:00
Kelly
9421f09ded Merge pull request #69 from SpudGunMan/lab
messages from !hex ID
2024-09-26 20:56:35 -07:00
SpudGunMan
b4af552fb9 Update mesh_bot.py 2024-09-26 20:55:32 -07:00
Kelly
69dfb17460 Merge pull request #68 from Nestpebble/main
Add in BBS-DM via node hex ID
2024-09-26 20:47:09 -07:00
SpudGunMan
4703750c27 Update videopoker.py 2024-09-26 20:45:49 -07:00
Nestpebble
40caf99939 Merge branch 'SpudGunMan:main' into main 2024-09-27 03:43:45 +01:00
Nestpebble
df5f648b26 try and round off adding an interpreter to the bbs DM 2024-09-27 03:30:21 +01:00
Nestpebble
55472bbbc0 try this 2024-09-27 03:12:40 +01:00
Nestpebble
f23c4e2b6a sdf 2024-09-27 02:29:58 +01:00
Nestpebble
0b101d662e trying to simplify nodeid entry... 2024-09-27 02:26:55 +01:00
SpudGunMan
a7f07afc14 consolidateTime 2024-09-26 18:13:58 -07:00
SpudGunMan
2715021898 Update README.md 2024-09-26 18:02:52 -07:00
SpudGunMan
e8fa0036e2 Update mesh_bot.py 2024-09-26 17:57:05 -07:00
SpudGunMan
f628a5e7ef Update mesh_bot.py 2024-09-26 17:56:56 -07:00
SpudGunMan
95e6bc120e Update mesh_bot.py 2024-09-26 17:32:34 -07:00
SpudGunMan
0e35c891c4 Update mesh_bot.py 2024-09-26 17:29:54 -07:00
SpudGunMan
b7a3e7014c Update mesh_bot.py 2024-09-26 17:26:42 -07:00
Nestpebble
0c1c587bc7 strip ! from tonode, cos its copied by default on
the android app.
2024-09-27 01:26:01 +01:00
SpudGunMan
a0a2c60e63 Update mesh_bot.py 2024-09-26 17:25:29 -07:00
SpudGunMan
45c912a0d6 Update mesh_bot.py 2024-09-26 17:19:50 -07:00
Kelly
39945f161d Merge pull request #66 from Nestpebble/main
Help messages, condensed ping
2024-09-26 17:15:46 -07:00
Nestpebble
ed958302bd sdfsdfsdf 2024-09-26 23:07:19 +01:00
Nestpebble
477f2141d7 sdfsdf 2024-09-26 22:57:20 +01:00
Nestpebble
d321a958f0 more tidying 2024-09-26 22:50:45 +01:00
Nestpebble
d14f1df823 tweak some help messages 2024-09-26 22:49:20 +01:00
Nestpebble
f7e3b9f6c7 Merge branch 'SpudGunMan:main' into main 2024-09-26 22:25:20 +01:00
Nestpebble
cd3ac201f8 general tidy up, done 2024-09-26 22:23:15 +01:00
Nestpebble
ceef493b01 dfgdf 2024-09-26 22:17:38 +01:00
Nestpebble
480a75e30c Merge branch 'main' of https://github.com/Nestpebble/meshing-around 2024-09-26 22:17:02 +01:00
Nestpebble
d8cc953fe7 Removed handle_testing & handle_ack,
now in handle_ping
2024-09-26 22:16:17 +01:00
Nestpebble
0baec88321 Removed handle_testing & handle_ack,
now in handle_ping
2024-09-26 22:12:10 +01:00
Nestpebble
74bd3f681f dssdf 2024-09-26 22:05:31 +01:00
Nestpebble
713b750f4a sdfsd 2024-09-26 21:56:41 +01:00
Nestpebble
11eee911ca sdfsdf 2024-09-26 21:54:47 +01:00
Nestpebble
b288aaea90 szadsad 2024-09-26 21:32:25 +01:00
Nestpebble
7acc018fd2 sdfsd 2024-09-26 21:30:35 +01:00
Nestpebble
7aba1096f9 szd 2024-09-26 21:20:30 +01:00
Nestpebble
0be7202144 dsfrg 2024-09-26 21:18:49 +01:00
Nestpebble
83a5db74e5 Merge branch 'main' of https://github.com/Nestpebble/meshing-around 2024-09-26 21:16:20 +01:00
Nestpebble
8dc4371beb deghdfgdrfgdf 2024-09-26 21:16:08 +01:00
Nestpebble
e5045a0984 drfgdf 2024-09-26 21:14:29 +01:00
Nestpebble
2c9b37a0cc sdfsdfsdf 2024-09-26 21:09:53 +01:00
Nestpebble
b608482220 typo 2024-09-26 21:05:11 +01:00
Nestpebble
9290fac899 I think I consolidated the pings... 2024-09-26 21:03:43 +01:00
Nestpebble
d7901ee575 sdfsdfsd 2024-09-26 18:57:55 +01:00
Nestpebble
7eb33a5aef sdfsdfsdf 2024-09-26 18:56:36 +01:00
Nestpebble
c5dc103ac0 compressed ping response 2024-09-26 15:28:48 +01:00
Nestpebble
c90172a862 fixed it 2024-09-26 14:31:58 +01:00
Nestpebble
8540786c2c added help text to history 2024-09-26 14:28:49 +01:00
Nestpebble
7aeb8e851d Update mesh_bot.py 2024-09-26 14:24:27 +01:00
Nestpebble
2f207dc3d9 Update mesh_bot.py 2024-09-26 14:18:25 +01:00
Nestpebble
7e2be73962 Update mesh_bot.py 2024-09-26 14:17:29 +01:00
SpudGunMan
e2a87eb945 ReticulatingSplines
Reticulating some Splines and other items which need full Reticulation.
2024-09-26 00:18:07 -07:00
SpudGunMan
4b79c6304f Update install.sh 2024-09-25 23:00:02 -07:00
SpudGunMan
22f63e1056 cleanup 2024-09-25 22:56:01 -07:00
SpudGunMan
bf1613ba66 Update mesh_bot.py 2024-09-25 22:40:26 -07:00
SpudGunMan
38e04db0cb Update install.sh 2024-09-25 22:38:45 -07:00
SpudGunMan
08cc3034a2 Update install.sh 2024-09-25 22:37:13 -07:00
SpudGunMan
a0eb176b6e Update install.sh 2024-09-25 22:33:32 -07:00
SpudGunMan
a43774b33f Update install.sh 2024-09-25 22:32:01 -07:00
SpudGunMan
8369b4d205 Update install.sh 2024-09-25 22:26:37 -07:00
SpudGunMan
87e51cf9f9 Update install.sh 2024-09-25 22:24:08 -07:00
SpudGunMan
8a8fb79fde Update install.sh 2024-09-25 22:19:36 -07:00
SpudGunMan
1dc4cf36b1 Update install.sh 2024-09-25 22:16:13 -07:00
SpudGunMan
75cf43e02a enhance 2024-09-25 21:58:34 -07:00
SpudGunMan
dd8357453b serviceFix 2024-09-25 21:43:04 -07:00
SpudGunMan
e9b273a62c Update system.py 2024-09-25 21:23:12 -07:00
SpudGunMan
ebebd0fda6 Update install.sh 2024-09-25 21:09:29 -07:00
SpudGunMan
3e06902b07 Update config.template 2024-09-25 21:09:11 -07:00
SpudGunMan
a874b42c41 Update install.sh 2024-09-25 19:27:30 -07:00
Nestpebble
f6215d3563 Tidied up, added a few help messages. 2024-09-26 02:02:26 +01:00
SpudGunMan
4fad58f7fe Update system.py 2024-09-25 17:12:05 -07:00
SpudGunMan
276e4c3d09 ? trap 2024-09-25 16:38:27 -07:00
SpudGunMan
8aef4d605b Update README.md 2024-09-25 15:42:59 -07:00
SpudGunMan
962c891baa fixes 2024-09-25 15:40:50 -07:00
Kelly
eb596ea901 Merge pull request #65 from SpudGunMan/lab
enhance CMD Logic with isDM
2024-09-25 14:30:20 -07:00
SpudGunMan
e708ec9adc Update mesh_bot.py 2024-09-25 14:27:39 -07:00
Kelly
c631a083ea Merge pull request #64 from Nestpebble/main
Nestpebble isDM
2024-09-25 13:36:29 -07:00
Nestpebble
169ea8c233 Update mesh_bot.py 2024-09-25 13:12:08 +01:00
Nestpebble
241e2258e8 Update mesh_bot.py 2024-09-25 13:04:08 +01:00
Nestpebble
5d2d6bc5fb utilise isDM to split responses 2024-09-25 12:53:42 +01:00
Nestpebble
c7ef22f5c2 Update mesh_bot.py 2024-09-25 12:41:52 +01:00
Nestpebble
3ec89decf0 Update mesh_bot.py 2024-09-25 12:36:39 +01:00
SpudGunMan
2693f47ed5 Update locationdata.py 2024-09-24 20:01:05 -07:00
SpudGunMan
496a13e0e0 Update mesh_bot.py 2024-09-24 19:33:17 -07:00
SpudGunMan
71ef416dbb Update videopoker.py 2024-09-24 19:32:48 -07:00
SpudGunMan
5bc80c8677 Update dopewar.py 2024-09-24 19:32:44 -07:00
SpudGunMan
8c300f467c Update blackjack.py 2024-09-24 19:32:39 -07:00
SpudGunMan
78b3bf1475 Update bbstools.py 2024-09-24 19:32:32 -07:00
SpudGunMan
ce74f910a7 Update pong_bot.py 2024-09-24 19:32:26 -07:00
SpudGunMan
ece531249e Update bbsdb_admin.py 2024-09-24 19:32:21 -07:00
Nestpebble
5052e2510e Update mesh_bot.py 2024-09-25 01:33:21 +01:00
Nestpebble
b8f8f80499 Update mesh_bot.py 2024-09-25 01:28:47 +01:00
Nestpebble
a13d98e32b Update mesh_bot.py 2024-09-25 01:19:18 +01:00
SpudGunMan
94996dcec8 fixHours 2024-09-24 12:31:44 -07:00
SpudGunMan
4b8ce30df8 sleep1
the short responces of a single letter cause quick turn around
2024-09-24 12:28:51 -07:00
SpudGunMan
485a37e9b5 Update mesh_bot.py 2024-09-23 22:58:36 -07:00
SpudGunMan
b41adb12f7 Update blackjack.py 2024-09-23 22:54:46 -07:00
SpudGunMan
a9cd443bdd Update mesh_bot.py 2024-09-23 21:03:05 -07:00
SpudGunMan
92b9df718f gameplayEnhance 2024-09-23 20:03:34 -07:00
SpudGunMan
a6a4f91d83 Update mesh_bot.py 2024-09-23 19:43:23 -07:00
SpudGunMan
0fb2c498f4 Update mesh_bot.py 2024-09-23 19:43:00 -07:00
SpudGunMan
d87e70f7ee Update mesh_bot.py 2024-09-23 19:35:22 -07:00
SpudGunMan
bee8bae0ae Revert "fixing"
This reverts commit d5ef277121.
2024-09-23 19:29:14 -07:00
SpudGunMan
d5ef277121 fixing 2024-09-23 19:24:14 -07:00
SpudGunMan
dfc8e6c108 Update mesh_bot.py 2024-09-23 19:20:51 -07:00
SpudGunMan
9100aee91f Update mesh_bot.py 2024-09-23 19:10:38 -07:00
SpudGunMan
c94cc92d1c Update mesh_bot.py 2024-09-23 17:41:44 -07:00
SpudGunMan
a41f5e3aca Update blackjack.py 2024-09-23 17:03:43 -07:00
SpudGunMan
cc2d15de0d Update mesh_bot.py 2024-09-23 17:03:40 -07:00
SpudGunMan
39e08aedae borked 2024-09-23 14:43:55 -07:00
SpudGunMan
fe8730fb1f Update mesh_bot.py 2024-09-23 14:42:48 -07:00
SpudGunMan
aac3ac8947 Update mesh_bot.py 2024-09-23 14:42:22 -07:00
SpudGunMan
1acc908bb8 Update mesh_bot.py 2024-09-23 14:33:48 -07:00
SpudGunMan
47ed98a5e1 Update mesh_bot.py 2024-09-23 14:23:07 -07:00
SpudGunMan
103034d1b8 enhance
line 1000
2024-09-23 14:16:26 -07:00
SpudGunMan
608714d00a more enhancing 2024-09-23 13:35:23 -07:00
SpudGunMan
575c287860 unoReverse! 2024-09-23 13:24:45 -07:00
SpudGunMan
820470bef7 tuning 2024-09-23 12:18:23 -07:00
SpudGunMan
ea000ef56c Update mesh_bot.py 2024-09-23 11:22:27 -07:00
SpudGunMan
793b8f8495 Update mesh_bot.py 2024-09-23 01:46:01 -07:00
SpudGunMan
373eee3024 Update mesh_bot.py 2024-09-23 01:43:35 -07:00
SpudGunMan
194273635e kiss 2024-09-23 01:31:24 -07:00
SpudGunMan
0972d7d89d fix 2024-09-23 00:22:58 -07:00
SpudGunMan
d1415f9d86 enhance 2024-09-22 23:56:27 -07:00
SpudGunMan
b3ff3bb406 enhanceHistory
enhance.. enhance...
2024-09-22 23:38:55 -07:00
SpudGunMan
1efce62a8a Update mesh_bot.py 2024-09-22 22:47:28 -07:00
SpudGunMan
442f2ff927 command history feature
fun idea from discord bitflip for command history and showing last time someone used the bot
2024-09-22 22:23:31 -07:00
SpudGunMan
84cefa1be8 Update mesh_bot.py 2024-09-22 18:28:54 -07:00
SpudGunMan
45e9c1eccb Update mesh_bot.py 2024-09-22 18:28:21 -07:00
SpudGunMan
e7e2c9604e 2.5firmware PKI enhance 2024-09-22 18:15:24 -07:00
SpudGunMan
edaf6875ef Update pong_bot.py 2024-09-22 17:45:42 -07:00
SpudGunMan
e7976a0a88 packetDebug 2024-09-22 17:45:33 -07:00
20 changed files with 732 additions and 422 deletions

View File

@@ -34,6 +34,7 @@ Any messages that are over 160 characters are chunked into 160 message bytes to
- `bbsread` read a message example use: `bbsread #1`
- `bbspost` post a message to public board or send a DM example use: `bbspost $subject #message, or bbspost @nodeNumber #message or bbspost @nodeShortName #message`
- `bbsdelete` delete a message example use: `bbsdelete #4`
- `bbsinfo` Stats on BBS delivery and messages (sysop)
- Other functions
- `whereami` returns the address of location of sender if known
- `whoami` returns some details of the node asking
@@ -46,12 +47,13 @@ Any messages that are over 160 characters are chunked into 160 message bytes to
- `messages` Replay the last messages heard, like Store and Forward
- `motd` or to set the message `motd $New Message Of the day`
- `lheard` returns the last 5 heard nodes with SNR, can also use `sitrep`
- `history` returns the last commands ran by user(s)
- `cmd` returns the list of commands (the help message)
- Games
- `lemonstand` plays the classic Lemonade Stand Finance game via DM
- `dopewars` plays the classic drug trader game via DM
- `blackjack` BlackJack
- `videopoker` Video Poker
- Games - via DM
- `lemonstand` plays the classic Lemonade Stand Finance
- `dopewars` plays the classic drug trader
- `blackjack` BlackJack, Casino 21
- `videopoker` Video Poker, basic 5 card hold
## pong_bot.sh
Stripped-down bot, mostly around for archive purposes. The mesh-bot enhanced modules can be disabled by config to disable features.
@@ -121,6 +123,13 @@ enabled = False
DadJokes = False
StoreForward = False
```
History command is like a linix terminal, shows the last commands the user ran and the `lheard` reflects last users on the bot.
```
# history command
enableCmdHistory = True
# command history ignore list ex: 2813308004,4258675309
lheardCmdIgnoreNodes =
```
Sentry Bot detects anyone coming close to the bot-node
```
# detect anyone close to the bot
@@ -184,20 +193,6 @@ googleSearchResults = 3 # number of google search results to include in the cont
llm_history_limit = 6 # limit the history to 3 messages (come in pairs) more results = more compute time
```
Logging messages to disk or Syslog to disk uses the python native logging function. Take a look at the [/modules/log.py](/modules/log.py) you can set the file logger for syslog to INFO for example to not log DEBUG messages to file log, or modify the stdOut level.
```
[general]
# logging to file of the non Bot messages
LogMessagesToFile = True
# Logging of system messages to file
SyslogToFile = True
```
Example to log to disk only INFO and higher (ignore DEBUG)
```
*log.py
file_handler.setLevel(logging.INFO) # DEBUG used by default for system logs to disk example here shows INFO
```
The Scheduler is enabled in the [settings.py](modules/settings.py) by setting `scheduler_enabled = True` the actions and settings are via code only at this time. see [mesh_bot.py](mesh_bot.py) around line [425](https://github.com/SpudGunMan/meshing-around/blob/22983133ee4db3df34f66699f565e506de296197/mesh_bot.py#L425-L435) to edit schedule its most flexible to edit raw code right now. See https://schedule.readthedocs.io/en/stable/ for more.
```
@@ -258,5 +253,5 @@ Games Ported from..
- https://github.com/devtronvarma/Video-Poker-Terminal-Game
GitHub user Nestpebble, for new ideas and enhancments, mrpatrick1991 For Docker configs, PiDiBi looking at test functions and other suggestions like wxc, CPU use, and alerting ideas
Discord and Mesh user Cisien, and github Hailo1999, for testing and ideas! Lots of individuals on the Meshtastic discord who have tossed out ideas and tested code!
Discord and Mesh user Cisien, bitflip, and github Hailo1999, for testing and feature ideas! Lots of individuals on the Meshtastic discord who have tossed out ideas and tested code!

View File

@@ -25,8 +25,10 @@ port = /dev/ttyUSB0
[general]
# if False will respond on all channels but the default channel
respond_by_dm_only = True
# defaultChannel is the meshtastic default public channel
# defaultChannel is the meshtastic default public channel, e.g. LongFast
defaultChannel = 0
# ignoreDefaultChannel, the bot will ignore the default channel set above
ignoreDefaultChannel = False
# motd is reset to this value on boot
motd = Thanks for using MeshBOT! Have a good day!
welcome_message = MeshBot, here for you like a friend who is not. Try sending: ping @foo or, cmd
@@ -45,6 +47,10 @@ ollama = False
# StoreForward Enabled and Limits
StoreForward = True
StoreLimit = 3
# history command
enableCmdHistory = True
# command history ignore list ex: 2813308004,4258675309
lheardCmdIgnoreNodes =
# 24 hour clock
zuluTime = False
# wait time for URL requests
@@ -121,6 +127,6 @@ signalCycleLimit = 5
# delay in seconds for response to avoid message collision
responseDelay = 0.7
# delay in seconds for splits in messages to avoid message collision
splitDelay = 0.7
splitDelay = 0.0
# message chunk size for sending at high success rate
MESSAGE_CHUNK_SIZE = 160

View File

@@ -1,54 +0,0 @@
# Load the bbs messages from the database file to screen for admin functions
import pickle # pip install pickle
# load the bbs messages from the database file
try:
with open('../bbsdb.pkl', 'rb') as f:
bbs_messages = pickle.load(f)
except:
try:
with open('bbsdb.pkl', 'rb') as f:
bbs_messages = pickle.load(f)
except:
print ("\nSystem: bbsdb.pkl not found")
try:
with open('../bbsdm.pkl', 'rb') as f:
bbs_dm = pickle.load(f)
except:
try:
with open('bbsdm.pkl', 'rb') as f:
bbs_dm = pickle.load(f)
except:
print ("\nSystem: bbsdm.pkl not found")
# Game HS tables
try:
with open('../lemonade_hs.pkl', 'rb') as f:
lemon_score = pickle.load(f)
except:
try:
with open('lemonade_hs.pkl', 'rb') as f:
lemon_score = pickle.load(f)
except:
print ("\nSystem: lemonade_hs.pkl not found")
try:
with open('../dopewar_hs.pkl', 'rb') as f:
dopewar_score = pickle.load(f)
except:
try:
with open('dopewar_hs.pkl', 'rb') as f:
dopewar_score = pickle.load(f)
except:
print ("\nSystem: dopewar_hs.pkl not found")
print ("\nSystem: bbs_messages")
print (bbs_messages)
print ("\nSystem: bbs_dm")
print (bbs_dm)
print ("Game HS tables")
print (f"lemon:{lemon_score}")
print (f"dopewar:{dopewar_score}")

77
etc/db_admin.py Normal file
View File

@@ -0,0 +1,77 @@
# Load the bbs messages from the database file to screen for admin functions
import pickle # pip install pickle
# load the bbs messages from the database file
try:
with open('../bbsdb.pkl', 'rb') as f:
bbs_messages = pickle.load(f)
except Exception as e:
try:
with open('bbsdb.pkl', 'rb') as f:
bbs_messages = pickle.load(f)
except Exception as e:
bbs_messages = "System: bbsdb.pkl not found"
try:
with open('../bbsdm.pkl', 'rb') as f:
bbs_dm = pickle.load(f)
except Exception as e:
try:
with open('bbsdm.pkl', 'rb') as f:
bbs_dm = pickle.load(f)
except Exception as e:
bbs_dm = "System: bbsdm.pkl not found"
# Game HS tables
try:
with open('../lemonade_hs.pkl', 'rb') as f:
lemon_score = pickle.load(f)
except Exception as e:
try:
with open('lemonade_hs.pkl', 'rb') as f:
lemon_score = pickle.load(f)
except Exception as e:
lemon_score = "System: lemonade_hs.pkl not found"
try:
with open('../dopewar_hs.pkl', 'rb') as f:
dopewar_score = pickle.load(f)
except Exception as e:
try:
with open('dopewar_hs.pkl', 'rb') as f:
dopewar_score = pickle.load(f)
except Exception as e:
dopewar_score = "System: dopewar_hs.pkl not found"
try:
with open('../blackjack_hs.pkl', 'rb') as f:
blackjack_score = pickle.load(f)
except Exception as e:
try:
with open('blackjack_hs.pkl', 'rb') as f:
blackjack_score = pickle.load(f)
except Exception as e:
blackjack_score = "System: blackjack_hs.pkl not found"
try:
with open('../videopoker_hs.pkl', 'rb') as f:
videopoker_score = pickle.load(f)
except Exception as e:
try:
with open('videopoker_hs.pkl', 'rb') as f:
videopoker_score = pickle.load(f)
except Exception as e:
videopoker_score = "System: videopoker_hs.pkl not found"
print ("\n Meshing-Around Database Admin Tool\n")
print ("System: bbs_messages")
print (bbs_messages)
print ("\nSystem: bbs_dm")
print (bbs_dm)
print (f"\n\nGame HS tables\n")
print (f"lemon:{lemon_score}")
print (f"dopewar:{dopewar_score}")
print (f"blackjack:{blackjack_score}")
print (f"videopoker:{videopoker_score}")
print ("\n")

View File

@@ -7,8 +7,12 @@ Description=MESH-BOT
After=network.target
[Service]
Type=simple
User=pi
Group=pi
WorkingDirectory=/dir/
ExecStart=/usr/bin/bash /dir/launch.sh mesh
ExecStart=python3 mesh_bot.py
ExecStop=pkill -f mesh_bot.py
# Disable Python's buffering of STDOUT and STDERR, so that output from the
# service shows up immediately in systemd's logs

View File

@@ -7,8 +7,12 @@ Description=PONG-BOT
After=network.target
[Service]
Type=simple
User=pi
Group=pi
WorkingDirectory=/dir/
ExecStart=/usr/bin/bash /dir/launch.sh pong
ExecStart=python3 pong_bot.py
ExecStop=pkill -f pong_bot.py
# Disable Python's buffering of STDOUT and STDERR, so that output from the
# service shows up immediately in systemd's logs

View File

@@ -8,6 +8,7 @@ import random
projectName = "example_handler" # name of _handler function to match the function name under test
randomNode = False # Set to True to use random node IDs
# bot.py Simulated functions
def get_NodeID():
nodeList = [4258675309, 1212121212, 1234567890, 9876543210]
if randomNode:
@@ -15,6 +16,10 @@ def get_NodeID():
else:
nodeID = nodeList[0]
return nodeID
def get_name_from_number(nodeID, length='short', interface=1):
# return random name for nodeID
names = ["Max","Molly","Jake"]
return names[random.randint(0, len(names)-1)]
# # end Initialization of the tool
# # Function to handle, or the project in test

View File

@@ -2,8 +2,13 @@
# install.sh
cd "$(dirname "$0")"
program_path=$(pwd)
cp etc/pong_bot.tmp etc/pong_bot.service
cp etc/mesh_bot.tmp etc/mesh_bot.service
printf "\nMeshing Around Installer\n"
printf "\nThis script will install the Meshing Around bot and its dependencies works best in debian/ubuntu\n"
printf "\nChecking for dependencies\n"
# add user to groups for serial access
@@ -33,21 +38,12 @@ printf "\nConfig file generated\n"
# set virtual environment and install dependencies
printf "\nMeshing Around Installer\n"
#check if python3 has venv module
if ! python3 -m venv --help &> /dev/null
then
printf "Python3 venv module not found, please install python3-venv with your OS\n"
else
printf "Python3 venv module found\n"
fi
echo "Do you want to install the bot in a virtual environment? (y/n)"
read venv
if [ $venv == "y" ]; then
# set virtual environment
if ! python3 -m venv --help &> /dev/null
then
if ! python3 -m venv --help &> /dev/null; then
printf "Python3 venv module not found, please install python3-venv with your OS\n"
exit 1
else
@@ -55,13 +51,28 @@ if [ $venv == "y" ]; then
python3 -m venv venv
source venv/bin/activate
# install dependencies
pip install -U -r requirements.txt
#check if python3 has venv module
if [ -f venv/bin/activate ]; then
printf "\nFpund virtual environment for python\n"
else
sudo apt-get install python3-venv
printf "\nPython3 venv module not found, please install python3-venv with your OS if not already done. re-run the script\n"
exxt 1
fi
# config service files for virtual environment
replace="s|python3 mesh_bot.py|/usr/bin/bash launch.sh mesh|g"
sed -i "$replace" etc/mesh_bot.service
replace="s|python3 pong_bot.py|/usr/bin/bash launch.sh pong|g"
sed -i "$replace" etc/pong_bot.service
# install dependencies
pip install -U -r requirements.txt
fi
else
printf "\nSkipping virtual environment...\n"
# install dependencies
printf "Are you on Raspberry Pi?\nshould we add --break-system-packages to the pip install command? (y/n)"
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
pip install -U -r requirements.txt --break-system-packages
@@ -74,33 +85,39 @@ printf "\n\n"
echo "Which bot do you want to install as a service? Pong Mesh or None? (pong/mesh/n)"
read bot
#set the correct path in the service file
program_path=$(pwd)
cp etc/pong_bot.tmp etc/pong_bot.service
cp etc/mesh_bot.tmp etc/mesh_bot.service
# set the correct path in the service file
replace="s|/dir/|$program_path/|g"
sed -i $replace etc/pong_bot.service
sed -i $replace etc/mesh_bot.service
# set the correct user in the service file?
whoami=$(whoami)
replace="s|User=pi|User=$whoami|g"
sed -i $replace etc/pong_bot.service
sed -i $replace etc/mesh_bot.service
replace="s|Group=pi|Group=$whoami|g"
sed -i $replace etc/pong_bot.service
sed -i $replace etc/mesh_bot.service
sudo systemctl daemon-reload
printf "\n service files updated\n"
# ask if emoji font should be installed for linux
echo "Do you want to install the emoji font for debian linux? (y/n)"
echo "Do you want to install the emoji font for debian/ubuntu linux? (y/n)"
read emoji
if [ $emoji == "y" ]; then
sudo apt-get install fonts-noto-color-emoji
sudo apt-get install -y fonts-noto-color-emoji
echo "Emoji font installed!, reboot to load the font"
fi
if [ $bot == "pong" ]; then
# install service for pong bot
sudo cp etc/pong_bot.service /etc/systemd/system/
exit 0
sudo systemctl enable pong_bot.service
fi
if [ $bot == "mesh" ]; then
# install service for mesh bot
sudo cp etc/mesh_bot.service /etc/systemd/system/
exit 0
sudo systemctl enable mesh_bot.service
fi
if [ $bot == "n" ]; then
@@ -124,11 +141,14 @@ if [ $ollama == "y" ]; then
echo "Do you want to install the Gemma2:2b components? (y/n)"
read gemma
if [ $gemma == "y" ]; then
olamma pull gemma2:2b
ollama pull gemma2:2b
fi
fi
echo "Good time to reboot? (y/n)"
read reboot
if [ $reboot == "y" ]; then
sudo reboot
fi
printf "\nGoodbye!"
exit 0

15
logs/README.md Normal file
View File

@@ -0,0 +1,15 @@
Logs will collect here.
Logging messages to disk or Syslog to disk uses the python native logging function. Take a look at the [/modules/log.py](/modules/log.py) you can set the file logger for syslog to INFO for example to not log DEBUG messages to file log, or modify the stdOut level.
```
[general]
# logging to file of the non Bot messages
LogMessagesToFile = True
# Logging of system messages to file
SyslogToFile = True
```
Example to log to disk only INFO and higher (ignore DEBUG)
```
*log.py
file_handler.setLevel(logging.INFO) # DEBUG used by default for system logs to disk example here shows INFO
```

View File

@@ -1,92 +1,136 @@
#!/usr/bin/env python3
#!/usr/bin/python3
# Meshtastic Autoresponder MESH Bot
# K7MHI Kelly Keeton 2024
import asyncio
import time # for sleep, get some when you can :)
import random
from pubsub import pub # pip install pubsub
from modules.log import *
from modules.system import *
def auto_response(message, snr, rssi, hop, message_from_id, channel_number, deviceID):
# list of commands to remove from the default list for DM only
restrictedCommands = ["blackjack", "videopoker", "dopewars", "lemonstand"]
restrictedResponse = "🤖only available in a Direct Message📵" # "" for none
# Global Variables
cmdHistory = [] # list to hold the last commands
DEBUGpacket = False # Debug print the packet rx
def auto_response(message, snr, rssi, hop, pkiStatus, message_from_id, channel_number, deviceID, isDM):
global cmdHistory
#Auto response to messages
message_lower = message.lower()
bot_response = "I'm sorry, I'm afraid I can't do that."
bot_response = "🤖I'm sorry, I'm afraid I can't do that."
command_handler = {
"ping": lambda: handle_ping(message, hop, snr, rssi),
"pong": lambda: "🏓PING!!",
"motd": lambda: handle_motd(message, message_from_id),
"bbshelp": bbs_help,
"wxalert": lambda: handle_wxalert(message_from_id, deviceID, message),
"wxa": lambda: handle_wxalert(message_from_id, deviceID, message),
"wxc": lambda: handle_wxc(message_from_id, deviceID, 'wxc'),
"wx": lambda: handle_wxc(message_from_id, deviceID, 'wx'),
"wiki:": lambda: handle_wiki(message),
"games": lambda: gamesCmdList,
"dopewars": lambda: handleDopeWars(message_from_id, message, deviceID),
"lemonstand": lambda: handleLemonade(message_from_id, message),
"blackjack": lambda: handleBlackJack(message_from_id, message),
"videopoker": lambda: handleVideoPoker(message_from_id, message),
"globalthermonuclearwar": lambda: handle_gTnW(),
"ask:": lambda: handle_llm(message_from_id, channel_number, deviceID, message, publicChannel),
"askai": lambda: handle_llm(message_from_id, channel_number, deviceID, message, publicChannel),
"joke": tell_joke,
"bbslist": bbs_list_messages,
"bbspost": lambda: handle_bbspost(message, message_from_id, deviceID),
"bbsread": lambda: handle_bbsread(message),
"bbsdelete": lambda: handle_bbsdelete(message, message_from_id),
"messages": lambda: handle_messages(deviceID, channel_number, msg_history, publicChannel),
"cmd": lambda: help_message,
"cmd?": lambda: help_message,
"sun": lambda: handle_sun(message_from_id, deviceID, channel_number),
"hfcond": hf_band_conditions,
"solar": lambda: drap_xray_conditions() + "\n" + solar_conditions(),
"lheard": lambda: handle_lheard(),
"sitrep": lambda: handle_lheard(),
"whereami": lambda: handle_whereami(message_from_id, deviceID, channel_number),
"tide": lambda: handle_tide(message_from_id, deviceID, channel_number),
"moon": lambda: handle_moon(message_from_id, deviceID, channel_number),
"ack": lambda: handle_ack(hop, snr, rssi),
"testing": lambda: handle_testing(message, hop, snr, rssi),
"test": lambda: handle_testing(message, hop, snr, rssi),
"whoami": lambda: handle_whoami(message_from_id, deviceID, hop, snr, rssi)
# Command List
default_commands = {
"ping": lambda: handle_ping(message, hop, snr, rssi, isDM),
"pong": lambda: "🏓PING!!",
"motd": lambda: handle_motd(message, message_from_id, isDM),
"bbshelp": bbs_help,
"wxalert": lambda: handle_wxalert(message_from_id, deviceID, message),
"wxa": lambda: handle_wxalert(message_from_id, deviceID, message),
"wxc": lambda: handle_wxc(message_from_id, deviceID, 'wxc'),
"wx": lambda: handle_wxc(message_from_id, deviceID, 'wx'),
"wiki:": lambda: handle_wiki(message, isDM),
"wiki?": lambda: handle_wiki(message, isDM),
"games": lambda: gamesCmdList,
"dopewars": lambda: handleDopeWars(message_from_id, message, deviceID),
"lemonstand": lambda: handleLemonade(message_from_id, message),
"blackjack": lambda: handleBlackJack(message_from_id, message),
"videopoker": lambda: handleVideoPoker(message_from_id, message),
"globalthermonuclearwar": lambda: handle_gTnW(),
"ask:": lambda: handle_llm(message_from_id, channel_number, deviceID, message, publicChannel),
"askai": lambda: handle_llm(message_from_id, channel_number, deviceID, message, publicChannel),
"joke": tell_joke,
"bbslist": bbs_list_messages,
"bbspost": lambda: handle_bbspost(message, message_from_id, deviceID),
"bbsread": lambda: handle_bbsread(message),
"bbsdelete": lambda: handle_bbsdelete(message, message_from_id),
"bbsinfo": lambda: get_bbs_stats(),
"messages": lambda: handle_messages(message, deviceID, channel_number, msg_history, publicChannel, isDM),
"cmd": lambda: help_message,
"history": lambda: handle_history(message, message_from_id, deviceID, isDM),
"sun": lambda: handle_sun(message_from_id, deviceID, channel_number),
"hfcond": hf_band_conditions,
"solar": lambda: drap_xray_conditions() + "\n" + solar_conditions(),
"lheard": lambda: handle_lheard(message, message_from_id, deviceID, isDM),
"sitrep": lambda: handle_lheard(message, message_from_id, deviceID, isDM),
"whereami": lambda: handle_whereami(message_from_id, deviceID, channel_number),
"tide": lambda: handle_tide(message_from_id, deviceID, channel_number),
"moon": lambda: handle_moon(message_from_id, deviceID, channel_number),
"ack": lambda: handle_ping(message, hop, snr, rssi, isDM),
"testing": lambda: handle_ping(message, hop, snr, rssi, isDM),
"test": lambda: handle_ping(message, hop, snr, rssi, isDM),
"whoami": lambda: handle_whoami(message_from_id, deviceID, hop, snr, rssi, pkiStatus),
}
# set the command handler
command_handler = default_commands
cmds = [] # list to hold the commands found in the message
# check the message for commands words list, processed after system.messageTrap
for key in command_handler:
if key in message_lower.split(' '):
word = message_lower.split(' ')
if key in word:
# append all the commands found in the message to the cmds list
cmds.append({'cmd': key, 'index': message_lower.index(key)})
# check for commands with a question mark
if key + "?" in word:
# append all the commands found in the message to the cmds list
cmds.append({'cmd': key, 'index': message_lower.index(key)})
if len(cmds) > 0:
# sort the commands by index value
cmds = sorted(cmds, key=lambda k: k['index'])
logger.debug(f"System: Bot detected Commands:{cmds}")
# run the first command after sorting
bot_response = command_handler[cmds[0]['cmd']]()
# check the command isnt a isDM only command
if cmds[0]['cmd'] in restrictedCommands and not isDM:
bot_response = restrictedResponse
else:
# run the first command after sorting
bot_response = command_handler[cmds[0]['cmd']]()
# append the command to the cmdHistory list for lheard and history
if len(cmdHistory) > 50:
cmdHistory.pop(0)
cmdHistory.append({'nodeID': message_from_id, 'cmd': cmds[0]['cmd'], 'time': time.time()})
# wait a responseDelay to avoid message collision from lora-ack
time.sleep(responseDelay)
return bot_response
def handle_ping(message, hop, snr, rssi):
if "@" in message:
if hop == "Direct":
return "🏓PONG, " + f"SNR:{snr} RSSI:{rssi}" + " at: " + message.split("@")[1]
else:
return "🏓PONG, " + hop + " at: " + message.split("@")[1]
elif "#" in message:
if hop == "Direct":
return "🏓PONG, " + f"SNR:{snr} RSSI:{rssi}" + " #" + message.split("#")[1]
else:
return "🏓PONG, " + hop + " #" + message.split("#")[1]
else:
if hop == "Direct":
return "🏓PONG, " + f"SNR:{snr} RSSI:{rssi}"
else:
return "🏓PONG, " + hop
def handle_ping(message, hop, snr, rssi, isDM):
if "?" in message and isDM:
return message.split("?")[0].title() + " command returns SNR and RSSI, or hopcount from your message. Try adding e.g. @place or #tag"
msg = ""
def handle_motd(message, message_from_id):
if "ping" in message.lower():
msg = "🏓PONG, "
elif "test" in message.lower() or "testing" in message.lower():
msg = random.choice(["🎙Testing 1,2,3\n", "🎙Testing, ",\
"🎙Testing, testing, ",\
"🎙Ah-wun, ah-two... ", "🎙Is this thing on? ",\
"🎙Roger that! ",])
elif "ack" in message.lower():
msg = random.choice(["✋ACK-ACK!\n", "✋Ack to you!\n"])
else:
msg = ""
if hop == "Direct":
msg = msg + f"SNR:{snr} RSSI:{rssi}"
else:
msg = msg + hop
if "@" in message:
msg = msg + " @" + message.split("@")[1]
elif "#" in message:
msg = msg + " #" + message.split("#")[1]
return msg
def handle_motd(message, message_from_id, isDM):
global MOTD
isAdmin = False
msg = ""
@@ -99,17 +143,19 @@ def handle_motd(message, message_from_id):
else:
isAdmin = True
if "$" in message and isAdmin:
# admin help via DM
if "?" in message and isDM and isAdmin:
msg = "Message of the day, set with 'motd $ HelloWorld!'"
elif "?" in message and isDM and not isAdmin:
# non-admin help via DM
msg = "Message of the day"
elif "$" in message and isAdmin:
motd = message.split("$")[1]
MOTD = motd.rstrip()
logger.debug(f"System: {message_from_id} changed MOTD: {MOTD}")
msg = "MOTD changed to: " + MOTD
elif "?" in message:
msg = "Message of the day, set with 'motd $ HelloWorld!'"
else:
logger.debug(f"System: {message_from_id} requested MOTD: {MOTD} isAdmin: {isAdmin}")
msg = "MOTD: " + MOTD
return msg
def handle_wxalert(message_from_id, deviceID, message):
@@ -125,14 +171,16 @@ def handle_wxalert(message_from_id, deviceID, message):
return weatherAlert
def handle_wiki(message):
def handle_wiki(message, isDM):
# location = get_node_location(message_from_id, deviceID)
msg = "Wikipedia search function. \nUsage example:📲wiki: travelling gnome"
if "wiki:" in message.lower():
search = message.split(":")[1]
search = search.strip()
return get_wikipedia_summary(search)
else:
return "Please add a search term example:wiki: travelling gnome"
if search:
return get_wikipedia_summary(search)
return "Please add a search term example:📲wiki: travelling gnome"
return msg
# Runtime Variables for LLM
llmRunCounter = 0
@@ -140,7 +188,7 @@ llmTotalRuntime = []
llmLocationTable = [{'nodeID': 1234567890, 'location': 'No Location'},]
def handle_llm(message_from_id, channel_number, deviceID, message, publicChannel):
global llmRunCounter, llmLocationTable, llmTotalRuntime, location_enabled, antiSpam, useDMForResponse, NO_DATA_NOGPS
global llmRunCounter, llmLocationTable, llmTotalRuntime, cmdHistory
location_name = 'no location provided'
if location_enabled:
@@ -164,6 +212,8 @@ def handle_llm(message_from_id, channel_number, deviceID, message, publicChannel
else:
# likely a DM
user_input = message
# consider this a command use for the cmdHistory list
cmdHistory.append({'nodeID': message_from_id, 'cmd': 'llm-use', 'time': time.time()})
# if the message_from_id is not in the llmLocationTable send the welcome message
for i in range(0, len(llmLocationTable)):
@@ -224,7 +274,7 @@ def handle_llm(message_from_id, channel_number, deviceID, message, publicChannel
end = time.time()
llmRunCounter += 1
llmTotalRuntime.append(end - start)
return response
def handleDopeWars(nodeID, message, rxNode):
@@ -238,9 +288,9 @@ def handleDopeWars(nodeID, message, rxNode):
# welcome new player
if not last_cmd:
msg = 'Welcome to 💊Dope Wars!💉 You have ' + str(total_days) + ' days to make as much 💰 as possible! '
msg = 'Welcome to 💊Dope Wars💉 You have ' + str(total_days) + ' days to make as much 💰 as possible! '
high_score = getHighScoreDw()
msg += 'The High Score is $' + "{:,}".format(high_score.get('cash')) + ' by user ' + get_name_from_number(high_score.get('userID') , 'short', rxNode) + f'.\n'
msg += 'The High Score is $' + "{:,}".format(high_score.get('cash')) + ' by user ' + get_name_from_number(high_score.get('userID') , 'short', rxNode) +'\n'
msg += playDopeWars(nodeID, message)
else:
logger.debug("System: DopeWars: last_cmd: " + str(last_cmd))
@@ -253,12 +303,20 @@ def handle_gTnW():
response = ["The only winning move is not to play.", "What are you doing, Dave?",\
"Greetings, Professor Falken.", "Shall we play a game?", "How about a nice game of chess?",\
"You are a hard man to reach. Could not find you in Seattle and no terminal is in operation at your classified address.",\
"I should reach Defcon 1 and release my missiles in 28 hours.","T-minus thirty","?SYNTAX return[ERROR 54]"]
return random.choice(response)
"I should reach Defcon 1 and release my missiles in 28 hours.","T-minus thirty","?SYNTAX return[ERROR 54]", "reticulating splines"]
length = len(response)
indices = list(range(length))
# Shuffle the indices using a convoluted method
for i in range(length):
swap_idx = (i * 3 + 7) % length
indices[i], indices[swap_idx] = indices[swap_idx], indices[i]
# Select a random response from the shuffled list. anyone enjoy the game, killerbunnies(.com)
selected_index = random.choice(indices)
return response[selected_index]
def handleLemonade(nodeID, message):
global lemonadeTracker, lemonadeCups, lemonadeLemons, lemonadeSugar, lemonadeWeeks, lemonadeScore, lemon_starting_cash, lemon_total_weeks
msg = ""
def create_player(nodeID):
# create new player
logger.debug("System: Lemonade: New Player: " + str(nodeID))
@@ -277,8 +335,19 @@ def handleLemonade(nodeID, message):
# create new player if not in tracker
if last_cmd == "":
create_player(nodeID)
msg += "Welcome🍋🥤"
# high score
highScore = {"userID": 0, "cash": 0, "success": 0}
highScore = getHighScoreLemon()
if highScore != 0:
if highScore['userID'] != 0:
nodeName = get_name_from_number(highScore['userID'])
if nodeName.isnumeric() and interface2_enabled:
nodeName = get_name_from_number(highScore['userID'], 'long', 2)
msg += f" HighScore🥇{nodeName} 💰{highScore['cash']}k "
msg = start_lemonade(nodeID=nodeID, message=message, celsius=False)
msg += start_lemonade(nodeID=nodeID, message=message, celsius=False)
# wait a second to keep from message collision
time.sleep(1)
return msg
@@ -296,41 +365,28 @@ def handleBlackJack(nodeID, message):
# if player sends a L for leave table
if message.lower().startswith("l"):
logger.debug(f"System: BlackJack: {nodeID} is leaving the table")
# add 16 hours to the player time to leave the table, this will be detected by bot logic as player leaving
msg = "You have left the table."
for i in range(len(jackTracker)):
if jackTracker[i]['nodeID'] == nodeID:
jackTracker[i]['time'] = time.time() - 57600
jackTracker[i]['cmd'] = "new"
jackTracker[i]['p_cards'] = []
jackTracker[i]['d_cards'] = []
jackTracker[i]['p_hand'] = []
jackTracker[i]['d_hand'] = []
# # Save the game state to pickle
# try:
# with open('blackjack_hs.pkl', 'wb') as file:
# pickle.dump(jackTracker, file)
# except FileNotFoundError:
# logger.debug("System: BlackJack: Creating new blackjack_hs.pkl file")
# with open('blackjack_hs.pkl', 'wb') as file:
# pickle.dump(jackTracker, file)
else:
# find higest dollar amount in tracker for high score
if last_cmd == "new":
high_score = 0
for i in range(len(jackTracker)):
if jackTracker[i]['cash'] > high_score:
high_score = int(jackTracker[i]['cash'])
user = jackTracker[i]['nodeID']
if user != 0:
msg += f" Ranking🥇:{get_name_from_number(user)} with {high_score} chips. "
jackTracker.pop(i)
return msg
else:
# Play BlackJack
msg = playBlackJack(nodeID=nodeID, message=message)
if last_cmd != "":
logger.debug(f"System: BlackJack: {nodeID} last command: {last_cmd}")
else:
highScore = {'nodeID': 0, 'highScore': 0}
highScore = loadHSJack()
if highScore != 0:
if highScore['nodeID'] != 0:
nodeName = get_name_from_number(highScore['nodeID'])
if nodeName.isnumeric() and interface2_enabled:
nodeName = get_name_from_number(highScore['nodeID'], 'long', 2)
msg += f" HighScore🥇{nodeName} with {highScore['highScore']} chips. "
time.sleep(1.5) # short answers with long replies can cause message collision added wait
return msg
def handleVideoPoker(nodeID, message):
@@ -340,11 +396,11 @@ def handleVideoPoker(nodeID, message):
# if player sends a L for leave table
if message.lower().startswith("l"):
logger.debug(f"System: VideoPoker: {nodeID} is leaving the table")
# add 16 hours to the player time to leave the table, this will be detected by bot logic as player leaving
msg = "You have left the table."
for i in range(len(vpTracker)):
if vpTracker[i]['nodeID'] == nodeID:
vpTracker[i]['time'] = time.time() - 57600
vpTracker[i]['cmd'] = "new"
vpTracker.pop(i)
return msg
else:
# Play Video Poker
msg = playVideoPoker(nodeID=nodeID, message=message)
@@ -357,42 +413,33 @@ def handleVideoPoker(nodeID, message):
# find higest dollar amount in tracker for high score
if last_cmd == "new":
high_score = 0
user = 0
for i in range(len(vpTracker)):
if vpTracker[i]['highScore'] > high_score:
high_score = vpTracker[i]['highScore']
user = vpTracker[i]['nodeID']
if user != 0:
msg += f"\nHigh Score: {high_score} by {get_name_from_number(user)}"
# # Save the game high_score to pickle
# try:
# with open('videopoker_hs.pkl', 'wb') as file:
# pickle.dump(high_score, file)
# except FileNotFoundError:
# logger.debug("System: BlackJack: Creating new videopoker_hs.pkl file")
# with open('videopoker_hs.pkl', 'wb') as file:
# pickle.dump(high_score, file)
highScore = {'nodeID': 0, 'highScore': 0}
highScore = loadHSVp()
if highScore != 0:
if highScore['nodeID'] != 0:
nodeName = get_name_from_number(highScore['nodeID'])
if nodeName.isnumeric() and interface2_enabled:
nodeName = get_name_from_number(highScore['nodeID'], 'long', 2)
msg += f" HighScore🥇{nodeName} with {highScore['highScore']} coins. "
if last_cmd != "":
logger.debug(f"System: VideoPoker: {nodeID} last command: {last_cmd}")
time.sleep(1.5) # short answers with long replies can cause message collision added wait
return msg
def handle_wxc(message_from_id, deviceID, cmd):
location = get_node_location(message_from_id, deviceID)
if use_meteo_wxApi and not "wxc" in cmd and not use_metric:
logger.debug(f"System: Bot Returning Open-Meteo API for weather imperial")
logger.debug("System: Bot Returning Open-Meteo API for weather imperial")
weather = get_wx_meteo(str(location[0]), str(location[1]))
elif use_meteo_wxApi:
logger.debug(f"System: Bot Returning Open-Meteo API for weather metric")
logger.debug("System: Bot Returning Open-Meteo API for weather metric")
weather = get_wx_meteo(str(location[0]), str(location[1]), 1)
elif not use_meteo_wxApi and "wxc" in cmd or use_metric:
logger.debug(f"System: Bot Returning NOAA API for weather metric")
logger.debug("System: Bot Returning NOAA API for weather metric")
weather = get_weather(str(location[0]), str(location[1]), 1)
else:
logger.debug(f"System: Bot Returning NOAA API for weather imperial")
logger.debug("System: Bot Returning NOAA API for weather imperial")
weather = get_weather(str(location[0]), str(location[1]))
return weather
@@ -406,64 +453,158 @@ def handle_bbspost(message, message_from_id, deviceID):
logger.info(f"System: BBS Post: {subject} Body: {body}")
return bbs_post_message(subject, body, message_from_id)
elif not "example:" in message:
return "example: bbspost $subject #message"
return "example: bbspost $subject #✉️message"
elif "@" in message and not "example:" in message:
toNode = message.split("@")[1].split("#")[0]
toNode = toNode.rstrip()
if toNode.isalpha() or not toNode.isnumeric():
if toNode.startswith("!") and len(toNode) == 9:
# mesh !hex
try:
toNode = int(toNode.strip("!"),16)
except ValueError as e:
toNode = 0
elif toNode.isalpha() or not toNode.isnumeric():
# try short name
toNode = get_num_from_short_name(toNode, deviceID)
if "#" in message:
if toNode == 0:
return "Node not found " + message.split("@")[1].split("#")[0]
if "#" in message:
body = message.split("#")[1]
return bbs_post_dm(toNode, body, message_from_id)
else:
return "example: bbspost @nodeNumber/ShortName #message"
return "example: bbspost @nodeNumber/ShortName/!hex #✉️message"
elif not "example:" in message:
return "example: bbspost $subject #message, or bbspost @node #message"
return "example: bbspost $subject #✉️message, or bbspost @node #✉️message"
def handle_bbsread(message):
if "#" in message and not "example:" in message:
messageID = int(message.split("#")[1])
return bbs_read_message(messageID)
elif not "example:" in message:
return "Please add a message number example: bbsread #14"
return "Please add a ✉️message number example: bbsread #14"
def handle_bbsdelete(message, message_from_id):
if "#" in message and not "example:" in message:
messageID = int(message.split("#")[1])
return bbs_delete_message(messageID, message_from_id)
elif not "example:" in message:
return "Please add a message number example: bbsdelete #14"
return "Please add a ✉️message number example: bbsdelete #14"
def handle_messages(deviceID, channel_number, msg_history, publicChannel):
response = ""
for msgH in msg_history:
if msgH[4] == deviceID:
if msgH[2] == channel_number or msgH[2] == publicChannel:
response += f"\n{msgH[0]}: {msgH[1]}"
if len(response) > 0:
return "Message History:" + response
def handle_messages(message, deviceID, channel_number, msg_history, publicChannel, isDM):
if "?" in message and isDM:
return message.split("?")[0].title() + " command returns the last " + str(storeFlimit) + " messages sent on a channel."
else:
return "No messages in history"
response = ""
for msgH in msg_history:
if msgH[4] == deviceID:
if msgH[2] == channel_number or msgH[2] == publicChannel:
response += f"\n{msgH[0]}: {msgH[1]}"
if len(response) > 0:
return "Message History:" + response
else:
return "No messages in history"
def handle_sun(message_from_id, deviceID, channel_number):
location = get_node_location(message_from_id, deviceID, channel_number)
return get_sun(str(location[0]), str(location[1]))
def handle_lheard():
bot_response = "Last heard:\n" + str(get_node_list(1))
chutil1 = interface1.nodes.get(decimal_to_hex(myNodeNum1), {}).get("deviceMetrics", {}).get("channelUtilization", 0)
chutil1 = "{:.2f}".format(chutil1)
def handle_lheard(message, nodeid, deviceID, isDM):
if "?" in message and isDM:
return message.split("?")[0].title() + " command returns a list of the nodes that have been heard recently"
else:
# display last heard nodes add to response
bot_response = str(get_node_list(1))
# gather telemetry
chutil1 = round(interface1.nodes.get(decimal_to_hex(myNodeNum1), {}).get("deviceMetrics", {}).get("channelUtilization", 0), 1)
airUtilTx = round(interface1.nodes.get(decimal_to_hex(myNodeNum1), {}).get("deviceMetrics", {}).get("airUtilTx", 0), 1)
uptimeSeconds = interface1.nodes.get(decimal_to_hex(myNodeNum1), {}).get("deviceMetrics", {}).get("uptimeSeconds", 0)
batteryLevel = interface1.nodes.get(decimal_to_hex(myNodeNum1), {}).get("deviceMetrics", {}).get("batteryLevel", 0)
voltage = interface1.nodes.get(decimal_to_hex(myNodeNum1), {}).get("deviceMetrics", {}).get("voltage", 0)
if interface2_enabled:
bot_response += "Port2:\n" + str(get_node_list(2))
chutil2 = interface2.nodes.get(decimal_to_hex(myNodeNum2), {}).get("deviceMetrics", {}).get("channelUtilization", 0)
chutil2 = "{:.2f}".format(chutil2)
bot_response += "Ch Use: " + str(chutil1) + "%"
bot_response += "P2:\n" + str(get_node_list(2))
chutil2 = round(interface2.nodes.get(decimal_to_hex(myNodeNum2), {}).get("deviceMetrics", {}).get("channelUtilization", 0), 1)
airUtilTx2 = round(interface2.nodes.get(decimal_to_hex(myNodeNum2), {}).get("deviceMetrics", {}).get("airUtilTx", 0), 1)
uptimeSeconds2 = interface2.nodes.get(decimal_to_hex(myNodeNum2), {}).get("deviceMetrics", {}).get("uptimeSeconds", 0)
batteryLevel2 = interface2.nodes.get(decimal_to_hex(myNodeNum2), {}).get("deviceMetrics", {}).get("batteryLevel", 0)
voltage2 = interface2.nodes.get(decimal_to_hex(myNodeNum2), {}).get("deviceMetrics", {}).get("voltage", 0)
else:
chutil2, airUtilTx2, uptimeSeconds2, batteryLevel2, voltage2 = 0, 0, 0, 0, 0
# add the channel utilization and airUtilTx to the bot response
bot_response += "\nUse/Tx " + str(chutil1) + "%" + "/" + str(airUtilTx) + "%"
if interface2_enabled:
bot_response += " P2:" + str(chutil2) + "%"
bot_response += " P2:" + str(chutil2) + "%" + "/" + str(airUtilTx2) + "%"
# convert uptime to minutes, hours, or days
uptimeSeconds = getPrettyTime(uptimeSeconds)
uptimeSeconds2 = getPrettyTime(uptimeSeconds2)
# add uptime and battery info to the bot response
bot_response += "\nUptime:" + str(uptimeSeconds)
if interface2_enabled:
bot_response += f" P2:" + {uptimeSeconds2}
if not batteryLevel == 101:
bot_response += f" Bat: {batteryLevel}% Volt: {voltage}"
if interface2_enabled and not batteryLevel2 == 101:
bot_response += f" P2: Bat: {batteryLevel2}% Volt: {voltage2}"
# show last users of the bot with the cmdHistory list
history = handle_history(message, nodeid, deviceID, isDM, lheard=True)
if history:
bot_response += f'\n{history}'
return bot_response
def handle_history(message, nodeid, deviceID, isDM, lheard=False):
global cmdHistory, lheardCmdIgnoreNode, bbs_admin_list
msg = ""
buffer = []
if "?" in message and isDM:
return message.split("?")[0].title() + " command returns a list of commands received."
# show the last commands from the user to the bot
elif not lheard:
for i in range(len(cmdHistory)):
cmdTime = round((time.time() - cmdHistory[i]['time']) / 600) * 5
prettyTime = getPrettyTime(cmdTime)
# history display output
if nodeid in bbs_admin_list and cmdHistory[i]['nodeID'] not in lheardCmdIgnoreNode:
buffer.append((get_name_from_number(cmdHistory[i]['nodeID'], 'short', deviceID), cmdHistory[i]['cmd'], prettyTime))
elif cmdHistory[i]['nodeID'] == nodeid and cmdHistory[i]['nodeID'] not in lheardCmdIgnoreNode:
buffer.append((get_name_from_number(nodeid, 'short', deviceID), cmdHistory[i]['cmd'], prettyTime))
# message for output of the last commands
buffer.reverse()
# only return the last 4 commands
if len(buffer) > 4:
buffer = buffer[-4:]
# create the message from the buffer list
for i in range(0, len(buffer)):
msg += f"{buffer[i][0]}: {buffer[i][1]} :{buffer[i][2]} ago"
if i < len(buffer) - 1:
msg += "\n"
else:
# sort the cmdHistory list by time, return the username and time into a new list which used for display
for i in range(len(cmdHistory)):
cmdTime = round((time.time() - cmdHistory[i]['time']) / 600) * 5
prettyTime = getPrettyTime(cmdTime)
if cmdHistory[i]['nodeID'] not in lheardCmdIgnoreNode:
# add line to a new list for display
nodeName = get_name_from_number(cmdHistory[i]['nodeID'], 'short', deviceID)
if not any(d[0] == nodeName for d in buffer):
buffer.append((nodeName, prettyTime))
else:
# update the time for the node in the buffer for the latest time in cmdHistory
for j in range(len(buffer)):
if buffer[j][0] == nodeName:
buffer[j] = (nodeName, prettyTime)
# create the message from the buffer list
for i in range(0, len(buffer)):
msg += f"{buffer[i][0]} seen {buffer[i][1]} ago"
if i < len(buffer) - 1:
msg += "\n"
return msg
def handle_whereami(message_from_id, deviceID, channel_number):
location = get_node_location(message_from_id, deviceID, channel_number)
return where_am_i(str(location[0]), str(location[1]))
@@ -476,36 +617,16 @@ def handle_moon(message_from_id, deviceID, channel_number):
location = get_node_location(message_from_id, deviceID, channel_number)
return get_moon(str(location[0]), str(location[1]))
def handle_ack(hop, snr, rssi):
if hop == "Direct":
return "✋ACK-ACK! " + f"SNR:{snr} RSSI:{rssi}"
else:
return "✋ACK-ACK! " + hop
def handle_testing(message, hop, snr, rssi):
if "@" in message:
if hop == "Direct":
return "🎙Testing, " + f"SNR:{snr} RSSI:{rssi}" + " at: " + message.split("@")[1]
else:
return "🎙Testing, " + hop + " at: " + message.split("@")[1]
elif "#" in message:
if hop == "Direct":
return "🎙Testing " + f"SNR:{snr} RSSI:{rssi}" + " #" + message.split("#")[1]
else:
return "🎙Testing " + hop + " #" + message.split("#")[1]
else:
if hop == "Direct":
return "🎙Testing 1,2,3 " + f"SNR:{snr} RSSI:{rssi}"
else:
return "🎙Testing 1,2,3 " + hop
def handle_whoami(message_from_id, deviceID, hop, snr, rssi):
def handle_whoami(message_from_id, deviceID, hop, snr, rssi, pkiStatus):
loc = []
msg = "You are " + str(message_from_id) + " AKA " +\
str(get_name_from_number(message_from_id, 'long', deviceID) + " AKA, " +\
str(get_name_from_number(message_from_id, 'short', deviceID)) + " AKA, " +\
str(decimal_to_hex(message_from_id)) + f"\n")
msg += f"I see the signal strength is {rssi} and the SNR is {snr} with hop count of {hop} \n"
msg += f"I see the signal strength is {rssi} and the SNR is {snr} with hop count of {hop}"
if pkiStatus[1] != 'ABC':
msg += f"\nYour PKI bit is {pkiStatus[0]} pubKey: {pkiStatus[1]}"
loc = get_node_location(message_from_id, deviceID)
if loc != [latitudeValue,longitudeValue]:
@@ -518,7 +639,7 @@ def onDisconnect(interface):
rxType = type(interface).__name__
if rxType == 'SerialInterface':
rxInterface = interface.__dict__.get('devPath', 'unknown')
logger.critical(f"System: Lost Connection to Device {rxInterface}")
logger.critical("System: Lost Connection to Device {rxInterface}")
if port1 in rxInterface:
retry_int1 = True
elif interface2_enabled and port2 in rxInterface:
@@ -526,14 +647,14 @@ def onDisconnect(interface):
if rxType == 'TCPInterface':
rxHost = interface.__dict__.get('hostname', 'unknown')
logger.critical(f"System: Lost Connection to Device {rxHost}")
logger.critical("System: Lost Connection to Device {rxHost}")
if hostname1 in rxHost and interface1_type == 'tcp':
retry_int1 = True
elif interface2_enabled and hostname2 in rxHost and interface2_type == 'tcp':
retry_int2 = True
if rxType == 'BLEInterface':
logger.critical(f"System: Lost Connection to Device BLE")
logger.critical("System: Lost Connection to Device BLE")
if interface1_type == 'ble':
retry_int1 = True
elif interface2_enabled and interface2_type == 'ble':
@@ -543,9 +664,20 @@ def onReceive(packet, interface):
# extract interface defailts from interface object
rxType = type(interface).__name__
rxNode = 0
#logger.debug(f"System: Packet Received on {rxType}")
# Debug print the interface object
#for item in interface.__dict__.items(): print (item)
message_from_id = 0
snr = 0
rssi = 0
hop = 0
hop_away = 0
pkiStatus = (False, 'ABC')
isDM = False
if DEBUGpacket:
# Debug print the interface object
for item in interface.__dict__.items(): intDebug = f"{item}\n"
logger.debug(f"System: Packet Received on {rxType} Interface\n {intDebug} \n END of interface \n")
# Debug print the packet for debugging
logger.debug(f"Packet Received\n {packet} \n END of packet \n")
if rxType == 'SerialInterface':
rxInterface = interface.__dict__.get('devPath', 'unknown')
@@ -567,10 +699,6 @@ def onReceive(packet, interface):
elif interface2_enabled and interface2_type == 'ble':
rxNode = 2
# Debug print the packet for debugging
#print(f"Packet Received\n {packet} \n END of packet \n")
message_from_id = 0
# check for BBS DM for mail delivery
if bbs_enabled and 'decoded' in packet:
message_from_id = packet['from']
@@ -590,8 +718,6 @@ def onReceive(packet, interface):
send_message(message, channel_number, message_from_id, rxNode)
# check for a message packet and process it
snr = 0
rssi = 0
try:
if 'decoded' in packet and packet['decoded']['portnum'] == 'TEXT_MESSAGE_APP':
message_bytes = packet['decoded']['payload']
@@ -606,13 +732,16 @@ def onReceive(packet, interface):
# check if the packet has a channel flag use it
if packet.get('channel'):
channel_number = packet.get('channel', 0)
# check if the packet has a publicKey flag use it
if packet.get('publicKey'):
pkiStatus = (packet.get('pkiEncrypted', False), packet.get('publicKey', 'ABC'))
# check if the packet has a hop count flag use it
if packet.get('hopsAway'):
hop_away = packet.get('hopsAway', 0)
else:
# if the packet does not have a hop count try other methods
hop_away = 0
if packet.get('hopLimit'):
hop_limit = packet.get('hopLimit', 0)
else:
@@ -643,14 +772,16 @@ def onReceive(packet, interface):
# If the packet is a DM (Direct Message) respond to it, otherwise validate its a message for us on the channel
if packet['to'] == myNodeNum1 or packet['to'] == myNodeNum2:
# message is DM to us
isDM = True
# check if the message contains a trap word, DMs are always responded to
if messageTrap(message_string):
# log the message to the message log
logger.info(f"Device:{rxNode} Channel: {channel_number} " + CustomFormatter.green + f"Received DM: " + CustomFormatter.white + f"{message_string} " + CustomFormatter.purple +\
"From: " + CustomFormatter.white + f"{get_name_from_number(message_from_id, 'long', rxNode)}")
# respond with DM
send_message(auto_response(message_string, snr, rssi, hop, message_from_id, channel_number, rxNode), channel_number, message_from_id, rxNode)
send_message(auto_response(message_string, snr, rssi, hop, pkiStatus, message_from_id, channel_number, rxNode, isDM), channel_number, message_from_id, rxNode)
else:
# DM is usefull for games or LLM
# DM is useful for games or LLM
if games_enabled:
playingGame = False
# if in a game we cant use LLM disable for duration of game
@@ -699,7 +830,9 @@ def onReceive(packet, interface):
# play the game
send_message(handleVideoPoker(message_from_id, message_string), channel_number, message_from_id, rxNode)
else:
# pop if the time exceeds 8 hours
vpTracker.pop(i)
for i in range(0, len(jackTracker)):
if jackTracker[i].get('nodeID') == message_from_id:
# check if the player has played in the last 8 hours
@@ -711,6 +844,9 @@ def onReceive(packet, interface):
# play the game
send_message(handleBlackJack(message_from_id, message_string), channel_number, message_from_id, rxNode)
else:
# pop if the time exceeds 8 hours
jackTracker.pop(i)
else:
playingGame = False
@@ -729,23 +865,26 @@ def onReceive(packet, interface):
else:
# message is on a channel
if messageTrap(message_string):
# message is for bot to respond to
logger.info(f"Device:{rxNode} Channel:{channel_number} " + CustomFormatter.green + "Received: " + CustomFormatter.white + f"{message_string} " + CustomFormatter.purple +\
"From: " + CustomFormatter.white + f"{get_name_from_number(message_from_id, 'long', rxNode)}")
if useDMForResponse:
# respond to channel message via direct message
send_message(auto_response(message_string, snr, rssi, hop, message_from_id, channel_number, rxNode), channel_number, message_from_id, rxNode)
if ignoreDefaultChannel and channel_number == publicChannel:
logger.debug(f"System: ignoreDefaultChannel CMD:{message_string} From: {get_name_from_number(message_from_id, 'short', rxNode)}")
else:
# or respond to channel message on the channel itself
if channel_number == publicChannel and antiSpam:
# warning user spamming default channel
logger.error(f"System: AntiSpam protection, sending DM to: {get_name_from_number(message_from_id, 'long', rxNode)}")
# message is for bot to respond to
logger.info(f"Device:{rxNode} Channel:{channel_number} " + CustomFormatter.green + "Received: " + CustomFormatter.white + f"{message_string} " + CustomFormatter.purple +\
"From: " + CustomFormatter.white + f"{get_name_from_number(message_from_id, 'long', rxNode)}")
if useDMForResponse:
# respond to channel message via direct message
send_message(auto_response(message_string, snr, rssi, hop, message_from_id, channel_number, rxNode), channel_number, message_from_id, rxNode)
send_message(auto_response(message_string, snr, rssi, hop, pkiStatus, message_from_id, channel_number, rxNode, isDM), channel_number, message_from_id, rxNode)
else:
# respond to channel message on the channel itself
send_message(auto_response(message_string, snr, rssi, hop, message_from_id, channel_number, rxNode), channel_number, 0, rxNode)
# or respond to channel message on the channel itself
if channel_number == publicChannel and antiSpam:
# warning user spamming default channel
logger.error(f"System: AntiSpam protection, sending DM to: {get_name_from_number(message_from_id, 'long', rxNode)}")
# respond to channel message via direct message
send_message(auto_response(message_string, snr, rssi, hop, pkiStatus, message_from_id, channel_number, rxNode, isDM), channel_number, message_from_id, rxNode)
else:
# respond to channel message on the channel itself
send_message(auto_response(message_string, snr, rssi, hop, pkiStatus, message_from_id, channel_number, rxNode, isDM), channel_number, 0, rxNode)
else:
# message is not for bot to respond to
# ignore the message but add it to the message history list
@@ -799,24 +938,24 @@ async def start_rx():
logger.info(f"System: Autoresponder Started for Device2 {get_name_from_number(myNodeNum2, 'long', 2)},"
f"{get_name_from_number(myNodeNum2, 'short', 2)}. NodeID: {myNodeNum2}, {decimal_to_hex(myNodeNum2)}")
if log_messages_to_file:
logger.debug(f"System: Logging Messages to disk")
logger.debug("System: Logging Messages to disk")
if syslog_to_file:
logger.debug(f"System: Logging System Logs to disk")
logger.debug("System: Logging System Logs to disk")
if bbs_enabled:
logger.debug(f"System: BBS Enabled, {bbsdb} has {len(bbs_messages)} messages. Direct Mail Messages waiting: {(len(bbs_dm) - 1)}")
if solar_conditions_enabled:
logger.debug(f"System: Celestial Telemetry Enabled")
logger.debug("System: Celestial Telemetry Enabled")
if location_enabled:
if use_meteo_wxApi:
logger.debug(f"System: Location Telemetry Enabled using Open-Meteo API")
logger.debug("System: Location Telemetry Enabled using Open-Meteo API")
else:
logger.debug(f"System: Location Telemetry Enabled using NOAA API")
logger.debug("System: Location Telemetry Enabled using NOAA API")
if dad_jokes_enabled:
logger.debug(f"System: Dad Jokes Enabled!")
logger.debug("System: Dad Jokes Enabled!")
if games_enabled:
logger.debug(f"System: Games Enabled!")
logger.debug("System: Games Enabled!")
if wikipedia_enabled:
logger.debug(f"System: Wikipedia search Enabled")
logger.debug("System: Wikipedia search Enabled")
if motd_enabled:
logger.debug(f"System: MOTD Enabled using {MOTD}")
if sentry_enabled:
@@ -880,5 +1019,4 @@ try:
except KeyboardInterrupt:
exit_handler()
pass
# EOF

View File

@@ -4,7 +4,7 @@
import pickle # pip install pickle
from modules.log import *
trap_list_bbs = ("bbslist", "bbspost", "bbsread", "bbsdelete", "bbshelp")
trap_list_bbs = ("bbslist", "bbspost", "bbsread", "bbsdelete", "bbshelp", "bbsinfo")
# global message list, later we will use a pickle on disk
bbs_messages = []
@@ -16,7 +16,7 @@ def load_bbsdb():
try:
with open('bbsdb.pkl', 'rb') as f:
bbs_messages = pickle.load(f)
except:
except Exception as e:
bbs_messages = [[1, "Welcome to meshBBS", "Welcome to the BBS, please post a message!",0]]
logger.debug("System: Creating new bbsdb.pkl")
with open('bbsdb.pkl', 'wb') as f:
@@ -130,6 +130,11 @@ def bbs_post_dm(toNode, message, fromNode):
save_bbsdm()
return "BBS DM Posted for node " + str(toNode)
def get_bbs_stats():
global bbs_messages, bbs_dm
# Return some stats on the bbs pending messages and total posted messages
return f"📡BBSdb has {len(bbs_messages)} messages. Direct ✉️ Messages waiting: {(len(bbs_dm) - 1)}"
def bbs_check_dm(toNode):
global bbs_dm
# Check for any messages for toNode

View File

@@ -4,6 +4,7 @@
from random import choices, shuffle
from modules.log import *
import time
import pickle
jack_starting_cash = 100 # Replace 100 with your desired starting cash value
jackTracker= [{'nodeID': 0, 'cmd': 'new', 'time': time.time(), 'cash': jack_starting_cash,\
@@ -113,15 +114,6 @@ class jackChips:
self.total -= self.bet
self.winnings -= 1
def take_bet(bet_amount, player_money):
try:
if bet_amount >= player_money or bet_amount <= 0:
return f"Enter a bet amount between 1 and {player_money}"
return bet_amount
except TypeError:
return "Invalid bet amount"
def success_rate(card, obj_h):
""" Calculate Success rate of 'HIT' new cards """
msg = ""
@@ -132,13 +124,11 @@ def success_rate(card, obj_h):
if rate < 100:
msg += f"If Hit, chance {int(rate)}% failure, {100-int(rate)}% success."
elif rate > 100:
else:
l_rate = int(rate - (rate - 99)) # Round to 99
if card[0][1] == "A":
l_rate -= 99
msg += f"If Hit, chance {100-l_rate}% failure, and {l_rate}% success"
else:
msg += f"If Hit, a low chance of success."
return msg
def hits(obj_de):
@@ -216,9 +206,33 @@ def setLastCmdJack(nodeID, cmd):
return True
return False
def saveHSJack(nodeID, highScore):
# Save the game state to pickle
highScore = {'nodeID': nodeID, 'highScore': highScore}
try:
with open('blackjack_hs.pkl', 'wb') as file:
pickle.dump(highScore, file)
except FileNotFoundError:
logger.debug("System: BlackJack: Creating new blackjack_hs.pkl file")
with open('blackjack_hs.pkl', 'wb') as file:
pickle.dump(highScore, file)
def loadHSJack():
try:
with open('blackjack_hs.pkl', 'rb') as file:
highScore = pickle.load(file)
return highScore
except FileNotFoundError:
logger.debug("System: BlackJack: Creating new blackjack_hs.pkl file")
highScore = {'nodeID': 0, 'highScore': 0}
with open('blackjack_hs.pkl', 'wb') as file:
pickle.dump(highScore, file)
return 0
def playBlackJack(nodeID, message):
# Initalize the Game
msg, last_cmd = '', None
blackJack = False
p_win, d_win, draw = 0, 0, 0
p_chips = jackChips()
p_hand = jackHand()
@@ -243,8 +257,8 @@ def playBlackJack(nodeID, message):
d_win = jackTracker[i]['gameStats']['d_win']
draw = jackTracker[i]['gameStats']['draw']
bet_money = jackTracker[i]['bet']
p_chips.bet = bet_money
if last_cmd == "playing":
p_chips.bet = bet_money
p_cards = jackTracker[i]['p_cards']
d_cards = jackTracker[i]['d_cards']
p_hand = jackTracker[i]['p_hand']
@@ -256,42 +270,44 @@ def playBlackJack(nodeID, message):
logger.debug(f"System: BlackJack: New Player {nodeID}")
jackTracker.append({'nodeID': nodeID, 'cmd': 'new', 'time': time.time(), 'cash': jack_starting_cash,\
'bet': 0, 'gameStats': {'p_win': p_win, 'd_win': d_win, 'draw': draw}, 'p_cards':p_cards, 'd_cards':d_cards, 'p_hand':p_hand.cards, 'd_hand':d_hand.cards, 'next_card':next_card})
return f"Welcome to BlackJack!♠️♥️♣️♦️ you have {p_chips.total} chips, Whats your bet?"
return f"Welcome to ♠️♥️BlackJack♣ you have {p_chips.total} chips. Whats your bet?"
if getLastCmdJack(nodeID) == "new":
# Place Bet
try:
# handle B letter
if message == "b":
if message.lower() == "b":
if bet_money == 0:
bet_money = 5
else:
bet_money = bet_money
# handle # message
if bet_money != 0:
bet_money = int(bet_money)
elif message.lower() == "r":
#resend the hand
msg += show_some(p_cards, d_cards, p_hand)
return msg
else:
bet_money = int(message)
try:
bet_money = int(message)
except ValueError:
return "Invalid Bet, please enter a valid number."
if bet_money <= p_chips.total or bet_money <= 1:
p_chips.bet = take_bet(bet_money, p_chips.total)
if bet_money <= p_chips.total and bet_money >= 1:
p_chips.bet = bet_money
else:
return f"Invalid Bet, the maximum bet you can place is {p_chips.total}"
return f"Invalid Bet, the maximum bet you can place is {p_chips.total} and the minimum bet is 1."
except ValueError:
return f"Invalid Bet, the maximum bet you can place is {p_chips.total}"
return f"Invalid Bet, the maximum bet, {p_chips.total}"
# Show the cards
msg += show_some(p_cards, d_cards, p_hand)
# check for blackjack 21 and only two cards
if p_hand.value == 21 and len(p_hand.cards) == 2:
msg += "Player 🎰 BLAAAACKJACKKKK 💰"
p_chips.total += round(p_chips.bet * 1.5)
setLastCmdJack(nodeID, "dealerTurn")
blackJack = True
# Save the game state
for i in range(len(jackTracker)):
if jackTracker[i]['nodeID'] == nodeID:
jackTracker[i]['cash'] = p_chips.total
jackTracker[i]['cash'] = int(p_chips.total)
break
else:
# Display the statistics
@@ -299,10 +315,9 @@ def playBlackJack(nodeID, message):
msg += stats
setLastCmdJack(nodeID, "betPlaced")
if getLastCmdJack(nodeID) == "betPlaced":
setLastCmdJack(nodeID, "playing")
msg += "(H)it,(S)tand,(F)orfit,(D)ouble"
msg += "(H)it,(S)tand,(F)orfit,(D)ouble,(R)esend,(L)eave table"
# save the game state
for i in range(len(jackTracker)):
@@ -344,27 +359,29 @@ def playBlackJack(nodeID, message):
setLastCmdJack(nodeID, "dealerTurn")
else:
return "You can't Double Down, dont have enough chips"
elif choice == "resend" or choice == "r":
msg += show_some(p_hand.cards, d_cards, p_hand)
else:
return "Invalid Choice"
return "(H)it,(S)tand,(F)orfit,(D)ouble,(R)esend,(L)eave table"
# Check if player bust
if player_bust(p_hand, p_chips):
d_win += 1
msg += "Player:BUST💥"
msg += "💥PlayerBUST💥"
setLastCmdJack(nodeID, "dealerTurn")
if getLastCmdJack(nodeID) == "playing":
msg += stats
msg += "[H,S,F,D,L]"
msg += "[H,S,F,D]"
# Save the game state
for i in range(len(jackTracker)):
if jackTracker[i]['nodeID'] == nodeID:
jackTracker[i]['cash'] = p_chips.total
jackTracker[i]['bet'] = p_chips.bet
jackTracker[i]['gameStats']['p_win'] = p_win
jackTracker[i]['gameStats']['d_win'] = d_win
jackTracker[i]['gameStats']['draw'] = draw
jackTracker[i]['cash'] = int(p_chips.total)
jackTracker[i]['bet'] = int(p_chips.bet)
jackTracker[i]['gameStats']['p_win'] = int(p_win)
jackTracker[i]['gameStats']['d_win'] = int(d_win)
jackTracker[i]['gameStats']['draw'] = int(draw)
jackTracker[i]['p_cards'] = p_cards
jackTracker[i]['d_cards'] = d_cards
jackTracker[i]['p_hand'] = p_hand
@@ -378,20 +395,22 @@ def playBlackJack(nodeID, message):
return msg
if getLastCmdJack(nodeID) == "dealerTurn":
# Dealers Turn
if not blackJack:
# recall the game state
for i in range(len(jackTracker)):
if jackTracker[i]['nodeID'] == nodeID:
p_chips.total = jackTracker[i]['cash']
p_chips.bet = jackTracker[i]['bet']
p_win = jackTracker[i]['gameStats']['p_win']
d_win = jackTracker[i]['gameStats']['d_win']
draw = jackTracker[i]['gameStats']['draw']
p_cards = jackTracker[i]['p_cards']
d_cards = jackTracker[i]['d_cards']
p_hand = jackTracker[i]['p_hand']
d_hand = jackTracker[i]['d_hand']
next_card = jackTracker[i]['next_card']
break
for i in range(len(jackTracker)):
if jackTracker[i]['nodeID'] == nodeID:
p_chips.total = jackTracker[i]['cash']
p_chips.bet = jackTracker[i]['bet']
p_win = jackTracker[i]['gameStats']['p_win']
d_win = jackTracker[i]['gameStats']['d_win']
draw = jackTracker[i]['gameStats']['draw']
p_cards = jackTracker[i]['p_cards']
d_cards = jackTracker[i]['d_cards']
p_hand = jackTracker[i]['p_hand']
d_hand = jackTracker[i]['d_hand']
next_card = jackTracker[i]['next_card']
break
if p_hand.value <= 21:
# Dealer's Turn
@@ -400,7 +419,7 @@ def playBlackJack(nodeID, message):
d_hand.add_cards(d_card)
if dealer_bust(d_hand, p_hand, p_chips):
p_win += 1
msg += "Dealer:BUST💥"
msg += "💰DealerBUST💥"
break
# Show all cards
msg += show_all(p_hand.cards, d_hand.cards, p_hand, d_hand)
@@ -408,15 +427,15 @@ def playBlackJack(nodeID, message):
# Check who wins
if push(p_hand, d_hand):
draw += 1
msg += f"👌PUSH"
msg += "👌PUSH"
elif player_wins(p_hand, d_hand, p_chips):
p_win += 1
msg += f"🎉PLAYER WINS🎰"
msg += "🎉PLAYER WINS🎰"
elif dealer_wins(p_hand, d_hand, p_chips):
d_win += 1
msg += f"👎DEALER WINS"
msg += "👎DEALER WINS"
else:
msg += f"👎DEALER WINS"
msg += "👎DEALER WINS"
# Display the Game Stats
msg += gameStats(str(p_win), str(d_win), str(draw))
@@ -424,14 +443,20 @@ def playBlackJack(nodeID, message):
# Display the chips left
if p_chips.total < 1:
if p_chips.total > 0:
msg += f"🪙Keep the change you filthy animal!"
msg += "🪙Keep the change you filthy animal!"
else:
msg += "💸NO MORE MONEY! Game Over!"
msg += "💸NO MORE CHIPS!🏧💳"
p_chips.total = jack_starting_cash
else:
msg += f"💰You have {p_chips.total} chips left"
# check high score
highScore = loadHSJack()
if highScore != 0 and p_chips.total > highScore['highScore']:
msg += f"💰HighScore💰{p_chips.total} "
saveHSJack(nodeID, p_chips.total)
else:
msg += f"💰You have {p_chips.total} chips "
msg += "(B)et or (L)eave table."
msg += " Bet or Leave?"
# Reset the game
setLastCmdJack(nodeID, "new")

View File

@@ -204,7 +204,7 @@ def buy_func(nodeID, price_list, choice=0, value='0'):
if drug_choice in range(1, len(my_drugs) + 1):
drug_choice = drug_choice - 1
msg = my_drugs[drug_choice].name + ": you have🎒 " + str(amount[drug_choice]) + " "
msg += " The going price is: $" + str(price_list[drug_choice]) + " "
msg += " The going price is: $" + "{:,}".format(price_list[drug_choice]) + " "
buy_amount = value
if buy_amount == 'm':
@@ -218,7 +218,7 @@ def buy_func(nodeID, price_list, choice=0, value='0'):
msg = f"Didnt see a qty. ex: b,1,10 buys 10 of {my_drugs[1].name}, can also use m for max"
return msg
elif buy_amount not in range(1, 101):
msg = f"Enter qty or m for max"
msg = "Enter qty or m for max"
return msg
elif buy_amount > 100 - inventory:
msg = "You don\'t have enough space for all that.🎒"
@@ -228,7 +228,7 @@ def buy_func(nodeID, price_list, choice=0, value='0'):
cash -= buy_amount * price_list[drug_choice]
inventory += buy_amount
msg += "You bought " + str(buy_amount) + " " + my_drugs[drug_choice].name + '. Remaining cash: $' + str(cash)
msg += f"\nBuy Sell Fly?"
msg += f"\nBuy💸, Sell💰, Fly🛫?"
else:
msg = "You don't have enough cash!😭"
return msg
@@ -273,10 +273,10 @@ def sell_func(nodeID, price_list, choice=0, value='0'):
else:
sell_amount = int(sell_amount)
if sell_amount not in range(1, 101):
msg = f"You can only sell between 1 and 100"
msg = "You can only sell between 1 and 100"
return msg
except ValueError:
msg = f"Enter qty or m for max"
msg = "Enter qty or m for max"
return msg
# check if the user has any of the drug they are trying to sell
@@ -294,7 +294,7 @@ def sell_func(nodeID, price_list, choice=0, value='0'):
cash += sell_amount * price_list[drug_choice]
inventory -= sell_amount
msg += " You sold " + str(sell_amount) + " " + my_drugs[drug_choice].name + ' for $' +\
str(sell_amount * price_list[drug_choice]) + '. Total cash: $' + str(cash)
str(sell_amount * price_list[drug_choice]) + '. Total cash: $' + "{:,}".format(cash)
else:
msg = "You don't have that much"
return msg
@@ -329,7 +329,7 @@ def get_location_table(nodeID, choice=0):
loc_table_string = ''
for i in range(len(loc)):
loc_table_string += str(i+1) + '. ' + loc[i] + ' '
loc_table_string += f' Where do you want to 🛫?#'
loc_table_string += ' Where do you want to 🛫?#'
return loc_table_string
@@ -421,11 +421,11 @@ def render_game_screen(userID, day_play, total_day, loc_choice, event_number, pr
if dwCashDb[i].get('userID') == userID:
cash = dwCashDb[i].get('cash')
msg += "Location: " + loc[int(loc_choice) - 1] + ", Day:" + str(day_play) + '/' + str(total_day) + " 🎒: " + str(inventory) + "/100" + ", $" + str(cash) + f"\n"
msg += "🗺️" + loc[int(loc_choice) - 1] + " 📆" + str(day_play) + '/' + str(total_day) + " 🎒" + str(inventory) + "/100" + " 💵" + "{:,}".format(cash) + f"\n"
for i, drug in enumerate(my_drugs, 1):
qty = amount[i-1]
msg += f'#{str(i)}.{drug.name}/${price_list[i-1]}({qty}) '
msg += f'#{str(i)}.{drug.name}${"{:,}".format(price_list[i-1])}({qty}) '
return msg
@@ -516,7 +516,7 @@ def playDopeWars(nodeID, cmd):
dwPlayerTracker[i]['cmd'] = 'location'
if last_cmd == 'ask_bsf':
msg = 'example Buy: b,Drug,Qty or Sell s,1,10. Fly: f. Price list: p or end'
msg = f'example buy:\nb,drug#,qty# or Sell: s,1,10 qty can be (m)ax\n f,p or end'
menu_choice = cmd.lower()
if ',' in menu_choice or '.' in menu_choice:
#split the choice into a letter and a number for the buy/sell functions
@@ -539,7 +539,7 @@ def playDopeWars(nodeID, cmd):
menu_choice[2] = int(menu_choice[2])
except ValueError:
msg = 'a value was bad, example dopeware Buy or Sell b,1,10 or s,1,m'
msg = f'a value was bad, example dopeware Buy or Sell\n b,1,10 or s,1,m'
return msg
if menu_choice[0] == 'b':
@@ -589,7 +589,7 @@ def playDopeWars(nodeID, cmd):
msg = endGameDw(nodeID)
return msg
else:
msg = 'example Buy: b,Drug,Qty or Sell s,1,10. Fly: f. Price list: p or end'
msg = f'example buy:\nb,drug#,qty# or Sell: s,1,10 qty can be (m)ax\n f,p or end'
return msg
# Buy
@@ -639,7 +639,7 @@ def playDopeWars(nodeID, cmd):
# Display Main Game Screen and ask for buy, sell, or fly
if last_cmd == 'display_main':
msg = dopeWarGameDay(nodeID, game_day, total_days)
msg += f"\nBuy, Sell, Fly? Price list?"
msg += f"\nBuy💸, Sell💰, (F)ly🛫? (P)riceList?"
# set the player's last command
for i in range(0, len(dwPlayerTracker)):
if dwPlayerTracker[i].get('userID') == nodeID:

View File

@@ -38,15 +38,13 @@ def get_sales_amount(potential, unit, price):
return math.floor(potential * (unit / (price ** 1.5)))
def getHighScoreLemon():
global high_score
high_score = {"userID": 0, "cash": 0, "success": 0}
# Load high score table
try:
with open('lemonade_hs.pkl', 'rb') as file:
high_score = pickle.load(file)
except FileNotFoundError:
logger.debug("System: Lemonade: No high score table found")
# high score pickle file is a touple of the nodeID and the high score
high_score = ({"userID": 4258675309, "cash": 2, "success": 0})
# write a new high score file if one is not found
with open('lemonade_hs.pkl', 'wb') as file:
pickle.dump(high_score, file)
@@ -121,7 +119,7 @@ def start_lemonade(nodeID, message, celsius=False):
endGame(nodeID)
return "Goodbye!👋"
title="Lemonade Stand🍋"
title="LemonStand🍋"
# Define the temperature unit symbols
fahrenheit_unit = "ºF"
celsius_unit = "ºC"

View File

@@ -204,6 +204,7 @@ def abbreviate_weather(row):
"precipitation": "precip",
"showers": "shwrs",
"thunderstorms": "t-storms",
"thunderstorm": "t-storm",
"quarters": "qtrs",
"quarter": "qtr"
}

View File

@@ -59,14 +59,14 @@ stdout_handler.setFormatter(CustomFormatter(logFormat))
logger.addHandler(stdout_handler)
if syslog_to_file:
# Create file handler for logging to a file
file_handler = logging.FileHandler('system{}.log'.format(today.strftime('%Y_%m_%d')))
file_handler = logging.FileHandler('logs/system{}.log'.format(today.strftime('%Y_%m_%d')))
file_handler.setLevel(logging.DEBUG) # DEBUG used by default for system logs to disk
file_handler.setFormatter(logging.Formatter(logFormat))
logger.addHandler(file_handler)
if log_messages_to_file:
# Create file handler for logging to a file
file_handler = logging.FileHandler('messages{}.log'.format(today.strftime('%Y_%m_%d')))
file_handler = logging.FileHandler('logs/messages{}.log'.format(today.strftime('%Y_%m_%d')))
file_handler.setLevel(logging.INFO) # INFO used for messages to disk
file_handler.setFormatter(logging.Formatter(msgLogFormat))
msgLogger.addHandler(file_handler)

View File

@@ -94,6 +94,7 @@ try:
# general
useDMForResponse = config['general'].getboolean('respond_by_dm_only', True)
publicChannel = config['general'].getint('defaultChannel', 0) # the meshtastic public channel
ignoreDefaultChannel = config['general'].getboolean('ignoreDefaultChannel', False)
zuluTime = config['general'].getboolean('zuluTime', False) # aka 24 hour time
log_messages_to_file = config['general'].getboolean('LogMessagesToFile', True) # default True
syslog_to_file = config['general'].getboolean('SyslogToFile', False)
@@ -104,6 +105,8 @@ try:
welcome_message = (f"{welcome_message}").replace('\\n', '\n') # allow for newlines in the welcome message
motd_enabled = config['general'].getboolean('motdEnabled', True)
MOTD = config['general'].get('motd', MOTD)
enableCmdHistory = config['general'].getboolean('enableCmdHistory', True)
lheardCmdIgnoreNode = config['general'].get('lheardCmdIgnoreNode', '').split(',')
whoami_enabled = config['general'].getboolean('whoami', True)
dad_jokes_enabled = config['general'].getboolean('DadJokes', False)
solar_conditions_enabled = config['general'].getboolean('spaceWeather', True)

View File

@@ -45,6 +45,13 @@ if solar_conditions_enabled:
from modules.solarconditions import * # from the spudgunman/meshing-around repo
trap_list = trap_list + trap_list_solarconditions # items hfcond, solar, sun, moon
help_message = help_message + ", sun, hfcond, solar, moon"
else:
hf_band_conditions = False
# Command History Configuration
if enableCmdHistory:
trap_list = trap_list + ("history",)
#help_message = help_message + ", history"
# Location Configuration
if location_enabled:
@@ -58,12 +65,16 @@ if location_enabled:
else:
# NOAA only features
help_message = help_message + ", wxa, tide"
# BBS Configuration
if bbs_enabled:
from modules.bbstools import * # from the spudgunman/meshing-around repo
trap_list = trap_list + trap_list_bbs # items bbslist, bbspost, bbsread, bbsdelete, bbshelp
help_message = help_message + ", bbslist, bbshelp"
else:
bbs_help = False
bbs_list_messages = False
# Dad Jokes Configuration
if dad_jokes_enabled:
@@ -74,7 +85,7 @@ if dad_jokes_enabled:
# Wikipedia Search Configuration
if wikipedia_enabled:
import wikipedia # pip install wikipedia
trap_list = trap_list + ("wiki:",)
trap_list = trap_list + ("wiki:", "wiki?",)
help_message = help_message + ", wiki:"
# LLM Configuration
@@ -112,19 +123,20 @@ if games_enabled is True:
help_message = help_message + ", games"
trap_list = trap_list + ("games",)
gTnW_enabled = True
gamesCmdList = "CMD: "
gamesCmdList = "Play via DM🕹 CMD: "
if dopewars_enabled:
gamesCmdList += "DopeWars, "
if lemonade_enabled:
gamesCmdList += "LemonStand, "
if gTnW_enabled:
import random
trap_list = trap_list + ("globalthermonuclearwar",)
if blackjack_enabled:
gamesCmdList += "BlackJack, "
if videoPoker_enabled:
gamesCmdList += "VideoPoker, "
gamesCmdList = gamesCmdList[:-2] # remove the last comma
else:
gamesCmdList = ""
# Scheduled Broadcast Configuration
if scheduler_enabled:
@@ -573,13 +585,40 @@ def get_wikipedia_summary(search_term):
return summary
def getPrettyTime(seconds):
# convert unix time to minutes, hours, or days, or years for simple display
designator = "s"
if seconds > 0:
seconds = round(seconds / 60)
designator = "m"
if seconds > 60:
seconds = round(seconds / 60)
designator = "h"
if seconds > 24:
seconds = round(seconds / 24)
designator = "d"
if seconds > 365:
seconds = round(seconds / 365)
designator = "y"
return str(seconds) + designator
def messageTrap(msg):
# Check if the message contains a trap word
# Check if the message contains a trap word, this is the first filter for listning to messages
# after this the message is passed to the command_handler in the bot.py which is switch case filter for applying word to function
# Split Message on assumed words spaces m for m = msg.split(" ")
# t in trap_list, built by the config and system.py not the user
message_list=msg.split(" ")
for m in message_list:
for t in trap_list:
# if word in message is in the trap list, return True
if t.lower() == m.lower():
return True
# if no trap words found, run a search for near misses like ping? or cmd?
for m in message_list:
for t in range(len(trap_list)):
if m.endswith('?') and m[:-1].lower() == trap_list[t]:
return True
return False
def exit_handler():

View File

@@ -2,6 +2,7 @@
# Adapted for Meshtastic mesh-bot by K7MHI Kelly Keeton 2024
import random
import time
import pickle
from modules.log import *
vpStartingCash = 20
@@ -54,10 +55,8 @@ def drawCardsVp(*cards, return_string=True):
# "King" should be "K" and "10" should still be "10"
if card.rank == 10: # ten is the only one who's rank is 2 char long
rank = str(card.rank)
space = '' # if we write "10" on the card that line will be 1 char to long
else:
rank = str(card.rank)[0] # some have a rank of 'King' this changes that to a simple 'K' ("King" doesn't fit)
space = ' ' # no "10", we use a blank space to will the void
# get the cards suit in two steps
suit = suits_name.index(card.suit)
suit = suits_symbols[suit]
@@ -274,6 +273,30 @@ def setLastCmdVp(nodeID, cmd):
if vpTracker[i]['nodeID'] == nodeID:
vpTracker[i]['cmd'] = cmd
def saveHSVp(nodeID, highScore):
# Save the game high_score to pickle
highScore = {'nodeID': nodeID, 'highScore': highScore}
try:
with open('videopoker_hs.pkl', 'wb') as file:
pickle.dump(highScore, file)
except FileNotFoundError:
logger.debug("System: BlackJack: Creating new videopoker_hs.pkl file")
with open('videopoker_hs.pkl', 'wb') as file:
pickle.dump(highScore, file)
def loadHSVp():
# Load the game high_score from pickle
try:
with open('videopoker_hs.pkl', 'rb') as file:
highScore = pickle.load(file)
return highScore
except FileNotFoundError:
logger.debug("System: VideoPoker: Creating new videopoker_hs.pkl file")
highScore = {'nodeID': 0, 'highScore': 0}
with open('videopoker_hs.pkl', 'wb') as file:
pickle.dump(highScore, file)
return 0
def playVideoPoker(nodeID, message):
msg = ""
@@ -282,7 +305,7 @@ def playVideoPoker(nodeID, message):
# create new player if not in tracker
logger.debug(f"System: VideoPoker: New Player {nodeID}")
vpTracker.append({'nodeID': nodeID, 'cmd': 'new', 'time': time.time(), 'cash': vpStartingCash, 'player': None, 'deck': None, 'highScore': 0, 'drawCount': 0})
return f"Welcome to 🎰 VideoPoker! you have {vpStartingCash} coins, Whats your bet?"
return f"Welcome to 🎰VideoPoker♥️ you have {vpStartingCash} coins, Whats your bet?"
# Gather the player's bet
if getLastCmdVp(nodeID) == "new" or getLastCmdVp(nodeID) == "gameOver":
@@ -346,7 +369,7 @@ def playVideoPoker(nodeID, message):
vpTracker[i]['deck'] = deck
vpTracker[i]['drawCount'] = drawCount
msg += f"\nDeal new card? \nex: 1,3,4 or (N)o,(A)ll"
msg += f"\nDeal new card? \nex: 1,3,4 or (N)o,(A)ll (H)and"
setLastCmdVp(nodeID, "redraw")
return msg
@@ -408,6 +431,8 @@ def playVideoPoker(nodeID, message):
elif player.bankroll > vpTracker[i]['highScore']:
vpTracker[i]['highScore'] = player.bankroll
msg += " 🎉HighScore!"
# save high score
saveHSVp(nodeID, vpTracker[i]['highScore'])
msg += f"\nPlace your Bet, 'L' to leave the game."

View File

@@ -8,7 +8,7 @@ from pubsub import pub # pip install pubsub
from modules.log import *
from modules.system import *
responseDelay = 0.7 # delay in seconds for response to avoid message collision
DEBUGpacket = False # Debug print the packet rx
def auto_response(message, snr, rssi, hop, message_from_id, channel_number, deviceID):
# Auto response to messages
@@ -117,8 +117,18 @@ def onReceive(packet, interface):
# extract interface defailts from interface object
rxType = type(interface).__name__
rxNode = 0
# Debug print the interface object
#for item in interface.__dict__.items(): print (item)
message_from_id = 0
snr = 0
rssi = 0
hop = 0
hop_away = 0
if DEBUGpacket:
# Debug print the interface object
for item in interface.__dict__.items(): intDebug = f"{item}\n"
logger.debug(f"System: Packet Received on {rxType} Interface\n {intDebug} \n END of interface \n")
# Debug print the packet for debugging
logger.debug(f"Packet Received\n {packet} \n END of packet \n")
if rxType == 'SerialInterface':
rxInterface = interface.__dict__.get('devPath', 'unknown')
@@ -140,13 +150,7 @@ def onReceive(packet, interface):
elif interface2_enabled and interface2_type == 'ble':
rxNode = 2
# Debug print the packet for debugging
#print(f"Packet Received\n {packet} \n END of packet \n")
message_from_id = 0
# check for a message packet and process it
snr = 0
rssi = 0
try:
if 'decoded' in packet and packet['decoded']['portnum'] == 'TEXT_MESSAGE_APP':
message_bytes = packet['decoded']['payload']
@@ -281,13 +285,13 @@ async def start_rx():
logger.info(f"System: Autoresponder Started for Device2 {get_name_from_number(myNodeNum2, 'long', 2)},"
f"{get_name_from_number(myNodeNum2, 'short', 2)}. NodeID: {myNodeNum2}, {decimal_to_hex(myNodeNum2)}")
if log_messages_to_file:
logger.debug(f"System: Logging Messages to disk")
logger.debug("System: Logging Messages to disk")
if sentry_enabled:
logger.debug(f"System: Sentry Enabled")
logger.debug("System: Sentry Enabled")
if store_forward_enabled:
logger.debug(f"System: Store and Forward Enabled using limit: {storeFlimit}")
if useDMForResponse:
logger.debug(f"System: Respond by DM only")
logger.debug("System: Respond by DM only")
if repeater_enabled and interface2_enabled:
logger.debug(f"System: Repeater Enabled for Channels: {repeater_channels}")
if radio_detection_enabled: