mirror of
https://github.com/SpudGunMan/meshing-around.git
synced 2026-08-08 18:03:33 +02:00
wordOfTheDay Games
Simple word fun, bingo and customizable word of the day lists via JSON files. Slot Machine for Emoji 🎰 shout out to pee-wee
This commit is contained in:
@@ -197,6 +197,10 @@ To use QuizMaster the bbs_admin_list is the QuizMaster, who can `q: start` and `
|
||||
Players can `q: join` to join the game, `q: leave` to leave the game, `q: score` to see their score, and `q: top` to see the top 3 players.
|
||||
To Answer a question, just type the answer prefixed with `q: <answer>`
|
||||
|
||||
#### Word of the Day Games
|
||||
Simple word fun, bingo and customizable word of the day lists via JSON files. Slot Machine for Emoji 🎰
|
||||
[modules/games/README.md](modules/games/README.md)
|
||||
|
||||
#### Survey
|
||||
To use the Survey feature edit the json files in data/survey multiple surveys are possible such as `survey snow` you can pull data back with `survey report` or `survey report snow`
|
||||
|
||||
|
||||
+18
@@ -1785,6 +1785,24 @@ def onReceive(packet, interface):
|
||||
# send a hello message as a DM
|
||||
if not train_qrz:
|
||||
send_message(f"Hello {name} {qrz_hello_string}", channel_number, message_from_id, rxNode)
|
||||
|
||||
# handle mini games
|
||||
if wordOfTheDay:
|
||||
#word of the day game play on non bot messages
|
||||
happened, old_entry, new_entry, bingo_win, bingo_message = theWordOfTheDay.did_it_happen(message_string)
|
||||
if happened:
|
||||
wordWas = old_entry['word']
|
||||
metaWas = old_entry['meta']
|
||||
msg = f"🎉 {get_name_from_number(message_from_id, 'long', rxNode)} found the Word of the Day🎊:\n {wordWas}, {metaWas}"
|
||||
send_message(msg, channel_number, 0, rxNode)
|
||||
if bingo_win:
|
||||
msg = f"🎉 {get_name_from_number(message_from_id, 'long', rxNode)} scored BINGO!🥳 {bingo_message}"
|
||||
send_message(msg, channel_number, 0, rxNode)
|
||||
|
||||
slotMachine = theWordOfTheDay.emojiMiniGame(message_string, emojiSeen=emojiSeen, nodeID=message_from_id, nodeInt=rxNode)
|
||||
if slotMachine:
|
||||
msg = f"🎉 {get_name_from_number(message_from_id, 'long', rxNode)} played the Slot Machine and got: {slotMachine} 🥳"
|
||||
send_message(msg, channel_number, 0, rxNode)
|
||||
else:
|
||||
# Evaluate non TEXT_MESSAGE_APP packets
|
||||
consumeMetadata(packet, rxNode, channel_number)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
## Word of the Day Game — Rules & Features
|
||||
|
||||
- **Word of the Day:**
|
||||
Each day, a new word is chosen from `data/wotd.json` (or a default list if missing). Mention the word (or its leet/1337 variants) in chat to win and trigger a new word.
|
||||
- **Bingo Mini-Game:**
|
||||
A random 3x3 bingo card of words, drawn from `data/bingo.json` (or a default list if missing). Mention words from the card in chat. Complete a row, column, or diagonal to win BINGO and get a new card.
|
||||
- **Emoji Mini-Game:**
|
||||
Use emojis in chat to:
|
||||
- Play a slot machine: send the same emoji several times in a row to hit the JACKPOT!
|
||||
- **Data Files:**
|
||||
- `data/wotd.json`: List of words and definitions for the Word of the Day.
|
||||
[
|
||||
{
|
||||
"word": "serendipity",
|
||||
"meta": "The occurrence of events by chance in a happy or beneficial way."
|
||||
},
|
||||
{
|
||||
"word": "ephemeral",
|
||||
"meta": "Lasting for a very short time."
|
||||
},
|
||||
{
|
||||
"word": "sonder",
|
||||
"meta": "The realization that each passerby has a life as vivid and complex as your own."
|
||||
}
|
||||
]
|
||||
- `data/bingo.json`: List of animal words for bingo cards.
|
||||
[
|
||||
"dog",
|
||||
"cat",
|
||||
"fish",
|
||||
"bird",
|
||||
"hamster",
|
||||
"rabbit",
|
||||
"turtle",
|
||||
"lizard",
|
||||
"snake"
|
||||
]
|
||||
@@ -5,7 +5,7 @@ from modules.log import *
|
||||
import random
|
||||
import time
|
||||
|
||||
# to molly and jake, I miss you both so much.
|
||||
# to (max), molly and jake, I miss you both so much.
|
||||
|
||||
if disable_emojis_in_games:
|
||||
X = "X"
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
#python word of the day game module for meshing-around bot
|
||||
from modules.log import *
|
||||
import random
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
from itertools import product
|
||||
|
||||
class WordOfTheDayGame:
|
||||
def __init__(self):
|
||||
default_word_list = [
|
||||
{'word': 'serendipity', 'meta': 'The occurrence of events by chance in a happy or beneficial way.'},
|
||||
{'word': 'ephemeral', 'meta': 'Lasting for a very short time.'},
|
||||
{'word': 'sonder', 'meta': 'The realization that each passerby has a life as vivid and complex as your own.'},
|
||||
{'word': 'petrichor', 'meta': 'A pleasant smell that frequently accompanies the first rain after a long period of warm, dry weather.'},
|
||||
]
|
||||
json_path = os.path.join('data', 'wotd.json')
|
||||
if os.path.exists(json_path):
|
||||
try:
|
||||
with open(json_path, 'r') as f:
|
||||
self.word_list = json.load(f)
|
||||
except FileNotFoundError:
|
||||
logger.debug("System: WoTd: Failed to load data/wotd.json, using default word list.")
|
||||
self.word_list = default_word_list
|
||||
except json.JSONDecodeError:
|
||||
logger.warning("System: WoTd: JSON decode error in data/wotd.json, example format: [{\"word\": \"example\", \"definition\": \"An example definition.\"}]")
|
||||
self.word_list = default_word_list
|
||||
else:
|
||||
logger.debug("System: WoTd: data/wotd.json not found, using default word list.")
|
||||
self.word_list = default_word_list
|
||||
|
||||
# Load bingo card words from JSON if available
|
||||
default_bingo_card = [
|
||||
"dog", "cat", "fish", "bird", "hamster", "rabbit", "turtle", "lizard", "snake", "frog",
|
||||
"horse", "cow", "pig", "sheep", "goat", "chicken", "duck", "turkey", "peacock", "parrot",
|
||||
"elephant", "lion", "tiger", "bear", "wolf", "fox", "deer", "moose", "zebra", "giraffe",
|
||||
"monkey", "ape", "chimpanzee", "gorilla", "orangutan", "kangaroo", "koala", "panda",
|
||||
"whale", "dolphin", "shark", "octopus", "crab", "lobster", "jellyfish", "seahorse",
|
||||
"ant", "bee", "butterfly", "dragonfly", "spider", "ladybug"
|
||||
]
|
||||
bingo_json_path = os.path.join('data', 'bingo.json')
|
||||
if os.path.exists(bingo_json_path):
|
||||
try:
|
||||
with open(bingo_json_path, 'r') as f:
|
||||
bingoCard = json.load(f)
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
logger.debug("System: WoTd: Failed to load data/bingo.json, using default bingo card. example format: [\"word1\", \"word2\", ...]")
|
||||
bingoCard = default_bingo_card
|
||||
else:
|
||||
logger.debug("System: WoTd: data/bingo.json not found, using default bingo card.")
|
||||
bingoCard = default_bingo_card
|
||||
|
||||
# Create a set for faster lookup
|
||||
self.bingoCardSet = set(bingoCard)
|
||||
|
||||
self.leet_dict = {
|
||||
'a': ['4', '@'],
|
||||
'b': ['8'],
|
||||
'e': ['3'],
|
||||
'i': ['1', '!', '|'],
|
||||
'l': ['1', '|', '7'],
|
||||
'o': ['0'],
|
||||
's': ['5', '$'],
|
||||
't': ['7', '+'],
|
||||
'g': ['9', '6'],
|
||||
}
|
||||
# Initialize the word of the day
|
||||
self.word_of_the_day_entry = random.choice(self.word_list)
|
||||
logger.debug(f"System: WoTd: Initialized with word of the day '{self.word_of_the_day_entry['word']}'.")
|
||||
# Initialize bingo card
|
||||
self.generate_bingo_card(3)
|
||||
logger.debug("System: BINGO: " + ". ".join(" | ".join(row) for row in self.bingo_card))
|
||||
|
||||
def get_emoji_type(self, emoji, randomReturn=False):
|
||||
smileys = "😀😁😂🤣😃😄😅😆😉😊😋😎😍😘🥰😗😙😚🙂🤗🤩🤔🤨😐😑😶🙄😏😣😥😮🤐😯😪😫😴😌😛😜😝🤤😒😓😔😕🙃🤑😲☹️🙁😖😞😟😤😢😭😦😧😨😩🤯😬😰😱🥵🥶😳🤪😵😡😠🤬😷🤒🤕🤢🤮🤧😇🥳🥺🤠"
|
||||
animals = "🐶🐱🐭🐹🐰🦊🐻🐼🐨🐯🦁🐮🐷🐽🐸🐵🙈🙉🙊🐒🐔🐧🐦🐤🐣🐥🦆🦅🦉🦇🐺🐗🐴🦄🐝🐛🦋🐌🐞🐜🦟🦗🕷️🕸️🐢🐍🦎🦂🦀🦞🦐🦑🐙🦑🐠🐟🐡🐬🦈🐳🐋🐊🐅🐆🦓🦍🦧🐘🦛🦏🐪🐫🦒🦘🐃🐂🐄🐎🐖🐏🐑🦙🐐🦌🐕🐩🦮🐕🦺🐈🐓🦃🦚🦜🦢🦩🕊️🐇🦝🦨🦡🦦🦥🐁🐀🐿️🦔"
|
||||
fruit = "🍎🍊🍌🍉🍇🍓🍒🍑🥭🍍🥥🥝🍅🥑🍆🥔🥕🌽🌶️🥒🥬🥦🧄🧅🍄🥜🌰"
|
||||
categories = {'smileys': smileys, 'animals': animals, 'fruit': fruit}
|
||||
if randomReturn:
|
||||
cat = random.choice(list(categories))
|
||||
return random.choice(categories[cat])
|
||||
for cat, chars in categories.items():
|
||||
if emoji in chars:
|
||||
return cat
|
||||
return False
|
||||
|
||||
def reset_word_of_the_day(self):
|
||||
logger.debug("System: WoTd: Resetting Word of the Day.")
|
||||
self.word_of_the_day_entry = random.choice(self.word_list)
|
||||
|
||||
def generate_leet_variants(self, word):
|
||||
chars = []
|
||||
for c in word.lower():
|
||||
if c in self.leet_dict:
|
||||
chars.append([c] + self.leet_dict[c])
|
||||
else:
|
||||
chars.append([c])
|
||||
variants = set()
|
||||
for combo in product(*chars):
|
||||
variant = ''.join(combo)
|
||||
variants.add(variant)
|
||||
if len(variants) > 128:
|
||||
break
|
||||
return variants
|
||||
|
||||
def did_it_happen(self, string_of_text=''):
|
||||
"""
|
||||
Check if the current word of the day (or its leet variants) appears in the text.
|
||||
Also check for a bingo win.
|
||||
Returns:
|
||||
(wotd_found, old_entry, new_entry, bingo_win, bingo_message)
|
||||
"""
|
||||
text = string_of_text.lower()
|
||||
words_in_text = set(text.split())
|
||||
word = self.word_of_the_day_entry['word'].lower()
|
||||
variants = self.generate_leet_variants(word)
|
||||
wotd_found = False
|
||||
old_entry = None
|
||||
new_entry = None
|
||||
|
||||
for variant in variants:
|
||||
if variant in words_in_text:
|
||||
old_entry = self.word_of_the_day_entry
|
||||
self.reset_word_of_the_day()
|
||||
new_entry = self.word_of_the_day_entry
|
||||
wotd_found = True
|
||||
break
|
||||
|
||||
bingo_win, bingo_message = self.b_i_n_g_o(string_of_text)
|
||||
return wotd_found, old_entry, new_entry, bingo_win, bingo_message
|
||||
|
||||
def generate_bingo_card(self, size=9):
|
||||
"""
|
||||
Generate a random bingo card of given size (size x size) from the bingoCardSet.
|
||||
Returns a 2D list representing the bingo card.
|
||||
"""
|
||||
words = random.sample(list(self.bingoCardSet), size * size)
|
||||
card = [words[i*size:(i+1)*size] for i in range(size)]
|
||||
self.bingo_card = card
|
||||
self.bingo_card_matches = [[False]*size for _ in range(size)]
|
||||
return card
|
||||
|
||||
def b_i_n_g_o(self, string_of_text=''):
|
||||
"""
|
||||
Check if any words in the text match the bingo card.
|
||||
If a row, column, or diagonal is fully matched, return True and the winning line.
|
||||
Otherwise, return False and None.
|
||||
"""
|
||||
if not hasattr(self, 'bingo_card'):
|
||||
logger.debug("System: WoTd: Generating new bingo card.")
|
||||
self.generate_bingo_card(3)
|
||||
|
||||
words_in_text = set(string_of_text.lower().split())
|
||||
size = len(self.bingo_card)
|
||||
# Mark matches
|
||||
for i in range(size):
|
||||
for j in range(size):
|
||||
if self.bingo_card[i][j].lower() in words_in_text:
|
||||
self.bingo_card_matches[i][j] = True
|
||||
|
||||
# Check rows
|
||||
for i in range(size):
|
||||
if all(self.bingo_card_matches[i]):
|
||||
winning_row = self.bingo_card[i]
|
||||
logger.debug("System: BINGO achieved, generating new bingo card.")
|
||||
self.generate_bingo_card(size) # Reset board after win
|
||||
return True, f"BINGO! Row {i+1}: {winning_row}"
|
||||
|
||||
# Check columns
|
||||
for j in range(size):
|
||||
if all(self.bingo_card_matches[i][j] for i in range(size)):
|
||||
col = [self.bingo_card[i][j] for i in range(size)]
|
||||
return True, f"BINGO! Column {j+1}: {col}"
|
||||
|
||||
# Check diagonals
|
||||
if all(self.bingo_card_matches[i][i] for i in range(size)):
|
||||
diag = [self.bingo_card[i][i] for i in range(size)]
|
||||
return True, f"BINGO! Diagonal: {diag}"
|
||||
if all(self.bingo_card_matches[i][size-1-i] for i in range(size)):
|
||||
diag = [self.bingo_card[i][size-1-i] for i in range(size)]
|
||||
return True, f"BINGO! Diagonal: {diag}"
|
||||
|
||||
return False, None
|
||||
|
||||
def extract_emojis(self, text):
|
||||
emojis = []
|
||||
for char in text:
|
||||
cp = ord(char)
|
||||
# Common emoji Unicode ranges
|
||||
if (
|
||||
0x1F600 <= cp <= 0x1F64F or # Emoticons
|
||||
0x1F300 <= cp <= 0x1F5FF or # Symbols & pictographs
|
||||
0x1F680 <= cp <= 0x1F6FF or # Transport & map symbols
|
||||
0x1F1E6 <= cp <= 0x1F1FF or # Regional indicator symbols
|
||||
0x2600 <= cp <= 0x26FF or # Misc symbols
|
||||
0x2700 <= cp <= 0x27BF or # Dingbats
|
||||
0x1F900 <= cp <= 0x1F9FF or # Supplemental symbols & pictographs
|
||||
0x1FA70 <= cp <= 0x1FAFF or # Symbols & pictographs extended-A
|
||||
0x2B50 == cp or # Star
|
||||
0x2B55 == cp # Heavy large circle
|
||||
):
|
||||
emojis.append(char)
|
||||
return emojis
|
||||
|
||||
def emojiMiniGame(self, string_of_text='', nodeID=0, nodeInt=1, emojiSeen=False):
|
||||
from modules.system import meshLeaderboard
|
||||
"""
|
||||
Track emoji usage, Returns a string if the mini-game is won, else None.
|
||||
If emojiSeen is False, only update mostMessages leaderboard and skip emoji logic.
|
||||
"""
|
||||
|
||||
# --- Always update mostMessages leaderboard ---
|
||||
if 'nodeMessageCounts' in meshLeaderboard and meshLeaderboard['nodeMessageCounts']:
|
||||
max_node = max(meshLeaderboard['nodeMessageCounts'], key=meshLeaderboard['nodeMessageCounts'].get)
|
||||
meshLeaderboard['mostMessages'] = {
|
||||
'nodeID': max_node,
|
||||
'value': meshLeaderboard['nodeMessageCounts'][max_node],
|
||||
'timestamp': time.time()
|
||||
}
|
||||
|
||||
|
||||
emoji = None # Placeholder: extract emoji from string_of_text if needed
|
||||
emojis = self.extract_emojis(string_of_text)
|
||||
if not emojiSeen and not emojis:
|
||||
return None
|
||||
logger.debug(f"System: WoTd: Emoji mini-game processing for nodeID {nodeID} with emojis: {emojis}")
|
||||
# --- 1. Update meshLeaderboard for emoji usage ---
|
||||
if 'emojiCounts' not in meshLeaderboard:
|
||||
meshLeaderboard['emojiCounts'] = {}
|
||||
if 'emojiTypeCounts' not in meshLeaderboard:
|
||||
meshLeaderboard['emojiTypeCounts'] = {}
|
||||
|
||||
meshLeaderboard['emojiCounts'].setdefault(nodeID, {})
|
||||
for emoji in emojis:
|
||||
meshLeaderboard['emojiCounts'][nodeID][emoji] = meshLeaderboard['emojiCounts'][nodeID].get(emoji, 0) + 1
|
||||
|
||||
# --- Update the leaderboard record for most emojis ---
|
||||
# Flatten per-node emoji counts to total per node
|
||||
emoji_totals = {nid: sum(emojicounts.values()) for nid, emojicounts in meshLeaderboard['emojiCounts'].items() if isinstance(emojicounts, dict)}
|
||||
if emoji_totals:
|
||||
max_node = max(emoji_totals, key=emoji_totals.get)
|
||||
meshLeaderboard['emojiCounts']['nodeID'] = max_node
|
||||
meshLeaderboard['emojiCounts']['value'] = emoji_totals[max_node]
|
||||
meshLeaderboard['emojiCounts']['timestamp'] = time.time()
|
||||
|
||||
# --- 2. Track most used of a type (e.g., smileys, animals, etc.) ---
|
||||
emoji_type = self.get_emoji_type(emoji)
|
||||
meshLeaderboard['emojiTypeCounts'].setdefault(emoji_type, {})
|
||||
meshLeaderboard['emojiTypeCounts'][emoji_type][emoji] = meshLeaderboard['emojiTypeCounts'][emoji_type].get(emoji, 0) + 1
|
||||
|
||||
# --- 3. Slot machine mini-game ---
|
||||
if 'emojiSlotWindow' not in meshLeaderboard:
|
||||
meshLeaderboard['emojiSlotWindow'] = []
|
||||
meshLeaderboard['emojiSlotWindow'].append(emoji)
|
||||
# Randomize jackpot length after each win
|
||||
if not hasattr(self, 'slot_jackpot_length'):
|
||||
self.slot_jackpot_length = random.choice([3,4,5]) # JackPot length can be 3, 4, or 5
|
||||
if len(meshLeaderboard['emojiSlotWindow']) > self.slot_jackpot_length:
|
||||
meshLeaderboard['emojiSlotWindow'].pop(0)
|
||||
|
||||
# --- 3a. Detect spam of 3 identical emojis in a row ---
|
||||
if len(meshLeaderboard['emojiSlotWindow']) >= 5:
|
||||
last_three = meshLeaderboard['emojiSlotWindow'][-3:]
|
||||
if len(set(last_three)) == 1:
|
||||
# Option: Randomly add an emoji to break the spam
|
||||
random_emoji = self.get_emoji_type('', randomReturn=True)
|
||||
meshLeaderboard['emojiSlotWindow'].append(random_emoji)
|
||||
logger.debug(f"System: WoTd: Detected emoji spam, added random emoji '{random_emoji}' to slot window.")
|
||||
# Optionally, you can still scramble or pop as well if you want
|
||||
random.shuffle(meshLeaderboard['emojiSlotWindow'])
|
||||
meshLeaderboard['emojiSlotWindow'].pop()
|
||||
|
||||
# # Debug: Show slot window status before jackpot check
|
||||
# logger.debug(
|
||||
# f"Emoji Slot Window: {meshLeaderboard['emojiSlotWindow']} | "
|
||||
# f"Jackpot Length: {self.slot_jackpot_length} | "
|
||||
# f"Unique: {set(meshLeaderboard['emojiSlotWindow'])} | "
|
||||
# f"Needed: {self.slot_jackpot_length - len(meshLeaderboard['emojiSlotWindow'])}"
|
||||
# )
|
||||
|
||||
# Jackpot: all emojis in window are the same
|
||||
if (
|
||||
len(meshLeaderboard['emojiSlotWindow']) == self.slot_jackpot_length and
|
||||
len(set(meshLeaderboard['emojiSlotWindow'])) == 1
|
||||
):
|
||||
winner_msg = f"🎰 JACKPOT! {emoji * self.slot_jackpot_length}"
|
||||
meshLeaderboard['emojiSlotWindow'] = []
|
||||
self.slot_jackpot_length = random.choice([3, 4, 5]) # Randomize jackpot length after win
|
||||
return winner_msg
|
||||
|
||||
return None
|
||||
|
||||
# Example usage:
|
||||
# theWordOfTheDay = WordOfTheDayGame()
|
||||
# happened, entry = theWordOfTheDay.did_it_happen("I love serendipity!")
|
||||
# if happened:
|
||||
# print(f"Found the word of the day: {entry['word']} - {entry['meta']}")
|
||||
+31
-10
@@ -217,7 +217,7 @@ if quiz_enabled:
|
||||
from modules.games.quiz import * # from the spudgunman/meshing-around repo
|
||||
trap_list = trap_list + trap_list_quiz # items quiz, q:
|
||||
help_message = help_message + ", quiz"
|
||||
games_enabled = True
|
||||
# games not enabled for quiz
|
||||
|
||||
if survey_enabled:
|
||||
from modules.survey import * # from the spudgunman/meshing-around repo
|
||||
@@ -225,6 +225,11 @@ if survey_enabled:
|
||||
help_message = help_message + ", survey"
|
||||
games_enabled = True
|
||||
|
||||
if wordOfTheDay:
|
||||
from modules.games.wodt import WordOfTheDayGame # from the spudgunman/meshing-around repo
|
||||
theWordOfTheDay = WordOfTheDayGame()
|
||||
# this runs in background and wont enable other games
|
||||
|
||||
# Games Configuration
|
||||
if games_enabled is True:
|
||||
help_message = help_message + ", games"
|
||||
@@ -1361,6 +1366,7 @@ def initializeMeshLeaderboard():
|
||||
'coldestTemp': {'nodeID': None, 'value': 999, 'timestamp': 0}, # 🥶
|
||||
'hottestTemp': {'nodeID': None, 'value': -999, 'timestamp': 0}, # 🥵
|
||||
'worstAirQuality': {'nodeID': None, 'value': 0, 'timestamp': 0}, # 💨
|
||||
'mostTMessages': {'nodeID': None, 'value': 0, 'timestamp': 0}, # 💬
|
||||
'mostMessages': {'nodeID': None, 'value': 0, 'timestamp': 0}, # 💬
|
||||
'highestDBm': {'nodeID': None, 'value': -999, 'timestamp': 0}, # 📶
|
||||
'weakestDBm': {'nodeID': None, 'value': 999, 'timestamp': 0}, # 📶
|
||||
@@ -1370,7 +1376,10 @@ def initializeMeshLeaderboard():
|
||||
'adminPackets': [], # 🚨
|
||||
'tunnelPackets': [], # 🚨
|
||||
'audioPackets': [], # ☎️
|
||||
'simulatorPackets': [] # 🤖
|
||||
'simulatorPackets': [], # 🤖
|
||||
'emojiCounts': {}, # Track emoji counts per node
|
||||
'emojiTypeCounts': {}, # Track emoji type counts
|
||||
'nodeMessageCounts': {} # Track total message counts per node
|
||||
}
|
||||
|
||||
initializeMeshLeaderboard()
|
||||
@@ -1393,10 +1402,10 @@ def consumeMetadata(packet, rxNode=0, channel=-1):
|
||||
node_message_count[nodeID] = node_message_count.get(nodeID, 0) + 1
|
||||
meshLeaderboard['nodeMessageCounts'] = node_message_count
|
||||
|
||||
if node_message_count[nodeID] > meshLeaderboard['mostMessages']['value']:
|
||||
meshLeaderboard['mostMessages']['value'] = node_message_count[nodeID]
|
||||
meshLeaderboard['mostMessages']['nodeID'] = nodeID
|
||||
meshLeaderboard['mostMessages']['timestamp'] = time.time()
|
||||
if node_message_count[nodeID] > meshLeaderboard['mostTMessages']['value']:
|
||||
meshLeaderboard['mostTMessages']['value'] = node_message_count[nodeID]
|
||||
meshLeaderboard['mostTMessages']['nodeID'] = nodeID
|
||||
meshLeaderboard['mostTMessages']['timestamp'] = time.time()
|
||||
|
||||
# consider Meta for highest and weakest DBm
|
||||
if packet.get('rxSnr') is not None:
|
||||
@@ -1759,11 +1768,11 @@ def saveLeaderboard():
|
||||
def loadLeaderboard():
|
||||
global meshLeaderboard
|
||||
try:
|
||||
defaults = {}
|
||||
initializeMeshLeaderboard()
|
||||
defaults = meshLeaderboard.copy()
|
||||
with open('data/leaderboard.pkl', 'rb') as f:
|
||||
meshLeaderboard = pickle.load(f)
|
||||
defaults.update(meshLeaderboard) # loaded values overwrite defaults
|
||||
loaded = pickle.load(f)
|
||||
defaults.update(loaded) # loaded values overwrite defaults
|
||||
meshLeaderboard = defaults
|
||||
if logMetaStats:
|
||||
logger.debug("System: Mesh Leaderboard loaded from leaderboard.pkl")
|
||||
@@ -1855,10 +1864,22 @@ def get_mesh_leaderboard(msg, fromID, deviceID):
|
||||
result += f"📶 Best RF: {value} dBm {get_name_from_number(nodeID, 'short', 1)}\n"
|
||||
|
||||
# Most Telemetry Messages
|
||||
if 'nodeMessageCounts' in meshLeaderboard and meshLeaderboard['mostTMessages']['nodeID'] is not None:
|
||||
nodeID = meshLeaderboard['mostTMessages']['nodeID']
|
||||
value = meshLeaderboard['mostTMessages']['value']
|
||||
result += f"💬 Most Telemetry: {value} {get_name_from_number(nodeID, 'short', 1)}\n"
|
||||
|
||||
# Most Emojis
|
||||
if 'nodeMessageCounts' in meshLeaderboard and meshLeaderboard['emojiCounts']['nodeID'] is not None:
|
||||
nodeID = meshLeaderboard['emojiCounts']['nodeID']
|
||||
value = meshLeaderboard['emojiCounts']['value']
|
||||
result += f"🤪 Most Emojis: {value} {get_name_from_number(nodeID, 'short', 1)}\n"
|
||||
|
||||
# Most Messages
|
||||
if 'nodeMessageCounts' in meshLeaderboard and meshLeaderboard['mostMessages']['nodeID'] is not None:
|
||||
nodeID = meshLeaderboard['mostMessages']['nodeID']
|
||||
value = meshLeaderboard['mostMessages']['value']
|
||||
result += f"💬 Most Telemetry: {value} {get_name_from_number(nodeID, 'short', 1)}\n"
|
||||
result += f"💬 Most Messages: {value} {get_name_from_number(nodeID, 'short', 1)}\n"
|
||||
|
||||
# Most WiFi devices seen
|
||||
if meshLeaderboard.get('mostPaxWiFi', {}).get('nodeID'):
|
||||
|
||||
Reference in New Issue
Block a user