reorganization + multicast works on Linux!

This commit is contained in:
2025-10-20 22:35:35 -05:00
parent 28e56feef1
commit 0db078dbe4
28 changed files with 65 additions and 82 deletions

View File

@@ -1,35 +1,3 @@
<h1 align="center"><strong>IntelliStar 2 Message Encoder / Data Collector</strong></h1> # py2Lib
# Requirements A python implementation of i2Lib from the original i2MessageEncoder.
* Properly set up interface for UDP.
* TWC API Key
## Completed Records
- [X] Aches and Pains
- [X] Air Quality
- [X] Airport Delays + National Airport delays
- [X] Alerts *(BERecord)*
- [X] Breathing
- [X] Current Conditions
- [X] Daily Forecasts
- [X] Hourly Forecasts
- [X] Heating and Cooling
- [X] Mosquito Activity
- [X] Pollen Forecasts
- [X] Tide Station Forecasts
- [X] Watering Needs
- [ ] Marine Forecasts
- [ ] Traffic Forecasts **(API access missing)**
# Usage instructions
1) Ensure that [Python is installed](https://www.python.org), or from your package repository (apt/winget).
2) [Download the code or git clone this URL] and unzip to the wanted directory.
3) Use command prompt to enter the directory of the scripts, then install package requirements:<br/>
```pip install -r requirements.txt``` <br/>
4) Copy **config.example.json** to **config.json** and edit to your specific config.
4) Drop your unit's **MachineProductCfg.xml** file into the root of the script
5) Run ``py main.py``
### Attributions & Disclaimers
Air Quality reports are powered by Copernicus Atmosphere Monitoring Service Information 2022.
Neither the European Commission nor ECMWF is responsible for any use that may be made of the Copernicus Information or Data it contains.

16
main.py
View File

@@ -1,8 +1,7 @@
import asyncio, aiofiles import asyncio, aiofiles
from asyncio.log import logger from asyncio.log import logger
from asyncore import loop from asyncore import loop
import logging,coloredlogs import logging
from radar import TWCRadarCollector
import os import os
from datetime import datetime from datetime import datetime
import recordTasks import recordTasks
@@ -13,7 +12,6 @@ with open("config.json", "r") as file:
cfg = json.load(file) cfg = json.load(file)
l = logging.getLogger(__name__) l = logging.getLogger(__name__)
coloredlogs.install(logger=l)
useRadarServer = cfg["useRadarServer"] useRadarServer = cfg["useRadarServer"]
@@ -33,9 +31,9 @@ async def createTemp():
os.mkdir('./.temp/output/satrad') os.mkdir('./.temp/output/satrad')
# Create msgId file for bit.py # Create msgId file for bit.py
#async with aiofiles.open('./.temp/msgId.txt', 'w') as msgId: async with aiofiles.open('./.temp/msgId.txt', 'w') as msgId:
#await msgId.write('694203') await msgId.write('694203')
#await msgId.close() await msgId.close()
else: else:
l.debug(".temp file exists") l.debug(".temp file exists")
return return
@@ -44,8 +42,10 @@ async def createTemp():
async def main(): async def main():
await createTemp() await createTemp()
mosaicTask = asyncio.create_task(recordTasks.updateMosaicTask()) if useRadarServer:
satradTask = asyncio.create_task(recordTasks.updateSatradTask()) mosaicTask = asyncio.create_task(recordTasks.updateMosaicTask())
satradTask = asyncio.create_task(recordTasks.updateSatradTask())
alertsTask = asyncio.create_task(recordTasks.alertsTask()) alertsTask = asyncio.create_task(recordTasks.alertsTask())
coTask = asyncio.create_task(recordTasks.coTask()) coTask = asyncio.create_task(recordTasks.coTask())
hfTask = asyncio.create_task(recordTasks.hfTask()) hfTask = asyncio.create_task(recordTasks.hfTask())

View File

@@ -0,0 +1 @@
# This file makes it to where the sys.path.append tomfoolery doesn't have to exist

View File

@@ -1,11 +1,11 @@
import asyncio import asyncio
import aiohttp import aiohttp
import aiofiles import aiofiles
import logging, coloredlogs import logging
from py2Lib import bit
from datetime import datetime from datetime import datetime
from os import path, listdir, remove from os import path, listdir, remove
import util.bit
# Open the config file and make it accessible via "cfg" # Open the config file and make it accessible via "cfg"
import json import json
@@ -13,7 +13,6 @@ with open("config.json", "r") as file:
cfg = json.load(file) cfg = json.load(file)
l = logging.getLogger(__name__) l = logging.getLogger(__name__)
coloredlogs.install(level="DEBUG")
async def getValidTimestamps(radarType:str) -> list: async def getValidTimestamps(radarType:str) -> list:
times = [] times = []
@@ -48,7 +47,6 @@ async def getValidTimestamps(radarType:str) -> list:
return times return times
async def downloadRadarFrames(radarType:str, timestamps: list) -> list: async def downloadRadarFrames(radarType:str, timestamps: list) -> list:
url_root = None
imagesToSend = [] imagesToSend = []
if (radarType == "satrad"): if (radarType == "satrad"):

View File

@@ -7,7 +7,7 @@ import aiohttp
import json import json
import time as epochTime import time as epochTime
import requests import requests
import logging,coloredlogs import logging
from os import path, mkdir, listdir, remove, cpu_count from os import path, mkdir, listdir, remove, cpu_count
from shutil import rmtree from shutil import rmtree
@@ -19,7 +19,6 @@ from wand.color import Color
radarType = "Radar-US" radarType = "Radar-US"
l = logging.getLogger(__name__) l = logging.getLogger(__name__)
coloredlogs.install()
upperLeftX,upperLeftY,lowerRightX,lowerRightY = 0,0,0,0 upperLeftX,upperLeftY,lowerRightX,lowerRightY = 0,0,0,0
xStart,xEnd,yStart,yEnd = 0,0,0,0 xStart,xEnd,yStart,yEnd = 0,0,0,0

View File

@@ -0,0 +1 @@
# This file makes it to where the sys.path.append tomfoolery doesn't have to exist

View File

@@ -1,14 +1,16 @@
import shutil import shutil
import requests import requests
import logging,coloredlogs import logging,coloredlogs
import py2Lib.bit
import util.machineProductCfg as MPC
import records.lfRecord as LFR
import gzip import gzip
from os import remove from os import remove
import xml.dom.minidom import xml.dom.minidom
import aiohttp, aiofiles, asyncio import aiohttp, aiofiles, asyncio
import util.bit
import util.machineProductCfg as MPC
import util.lfRecord as LFR
l = logging.getLogger(__name__) l = logging.getLogger(__name__)
coloredlogs.install() coloredlogs.install()

View File

@@ -9,9 +9,9 @@ import aiohttp, aiofiles, asyncio
l = logging.getLogger(__name__) l = logging.getLogger(__name__)
coloredlogs.install() coloredlogs.install()
import py2Lib.bit import util.bit
import util.machineProductCfg as MPC import util.machineProductCfg as MPC
import records.lfRecord as LFR import util.lfRecord as LFR
locationIds = [] locationIds = []
zipCodes = [] zipCodes = []

View File

@@ -6,9 +6,9 @@ import xml.dom.minidom
import logging,coloredlogs import logging,coloredlogs
import aiohttp, aiofiles, asyncio import aiohttp, aiofiles, asyncio
import py2Lib.bit import util.bit
import util.machineProductCfg as MPC import util.machineProductCfg as MPC
import records.lfRecord as LFR import util.lfRecord as LFR
l = logging.getLogger(__name__) l = logging.getLogger(__name__)
coloredlogs.install() coloredlogs.install()

View File

@@ -2,7 +2,6 @@ import requests
import json import json
import os import os
from datetime import datetime,timedelta from datetime import datetime,timedelta
from util.machineProductCfg import getAlertZones
import time import time
import pytz import pytz
import xml.dom.minidom import xml.dom.minidom
@@ -10,7 +9,11 @@ import shutil
import gzip import gzip
import logging,coloredlogs import logging,coloredlogs
import aiohttp, aiofiles, asyncio import aiohttp, aiofiles, asyncio
import py2Lib.bit
import util.bit
import util.machineProductCfg as MPC
import util.lfRecord as LFR
from util.machineProductCfg import getAlertZones
l = logging.getLogger(__name__) l = logging.getLogger(__name__)
coloredlogs.install() coloredlogs.install()

View File

@@ -7,9 +7,9 @@ import xml.dom.minidom
import logging,coloredlogs import logging,coloredlogs
import aiohttp, aiofiles, asyncio import aiohttp, aiofiles, asyncio
import py2Lib.bit import util.bit
import util.machineProductCfg as MPC import util.machineProductCfg as MPC
import records.lfRecord as LFR import util.lfRecord as LFR
l = logging.getLogger(__name__) l = logging.getLogger(__name__)
coloredlogs.install() coloredlogs.install()

View File

@@ -1,5 +1,4 @@
import requests import requests
import py2Lib.bit as bit
import gzip import gzip
import uuid import uuid
import os import os
@@ -8,9 +7,9 @@ import xml.dom.minidom
import logging,coloredlogs import logging,coloredlogs
import aiohttp, aiofiles, asyncio import aiohttp, aiofiles, asyncio
import py2Lib.bit import util.bit
import util.machineProductCfg as MPC import util.machineProductCfg as MPC
import records.lfRecord as LFR import util.lfRecord as LFR
l = logging.getLogger(__name__) l = logging.getLogger(__name__)
coloredlogs.install() coloredlogs.install()

View File

@@ -7,9 +7,9 @@ import xml.dom.minidom
import logging,coloredlogs import logging,coloredlogs
import aiohttp, aiofiles, asyncio import aiohttp, aiofiles, asyncio
import py2Lib.bit import util.bit
import util.machineProductCfg as MPC import util.machineProductCfg as MPC
import records.lfRecord as LFR import util.lfRecord as LFR
l = logging.getLogger(__name__) l = logging.getLogger(__name__)
coloredlogs.install() coloredlogs.install()

View File

@@ -1,9 +1,11 @@
import shutil import shutil
import requests import requests
import logging,coloredlogs import logging,coloredlogs
import py2Lib.bit
import util.bit
import util.machineProductCfg as MPC import util.machineProductCfg as MPC
import records.lfRecord as LFR import util.lfRecord as LFR
import gzip import gzip
from os import remove from os import remove
import xml.dom.minidom import xml.dom.minidom

View File

@@ -7,9 +7,9 @@ import xml.dom.minidom
import logging,coloredlogs import logging,coloredlogs
import aiohttp, aiofiles, asyncio, asyncio import aiohttp, aiofiles, asyncio, asyncio
import py2Lib.bit import util.bit
import util.machineProductCfg as MPC import util.machineProductCfg as MPC
import records.lfRecord as LFR import util.lfRecord as LFR
l = logging.getLogger(__name__) l = logging.getLogger(__name__)
coloredlogs.install() coloredlogs.install()

View File

@@ -1,9 +1,11 @@
import shutil import shutil
import requests import requests
import logging,coloredlogs import logging,coloredlogs
import py2Lib.bit
import util.bit
import util.machineProductCfg as MPC import util.machineProductCfg as MPC
import records.lfRecord as LFR import util.lfRecord as LFR
import gzip import gzip
from os import remove from os import remove
import xml.dom.minidom import xml.dom.minidom

View File

@@ -7,9 +7,9 @@ import xml.dom.minidom
import logging, coloredlogs import logging, coloredlogs
import aiohttp, aiofiles, asyncio import aiohttp, aiofiles, asyncio
import py2Lib.bit import util.bit
import util.machineProductCfg as MPC import util.machineProductCfg as MPC
import records.lfRecord as LFR import util.lfRecord as LFR
l = logging.getLogger(__name__) l = logging.getLogger(__name__)

View File

@@ -1,9 +1,11 @@
import shutil import shutil
import logging,coloredlogs import logging,coloredlogs
import datetime import datetime
import py2Lib.bit
import util.bit
import util.machineProductCfg as MPC import util.machineProductCfg as MPC
import records.lfRecord as LFR import util.lfRecord as LFR
import gzip import gzip
from os import remove from os import remove
import xml.dom.minidom import xml.dom.minidom

View File

@@ -1,9 +1,11 @@
import shutil import shutil
import requests import requests
import logging,coloredlogs import logging,coloredlogs
import py2Lib.bit
import util.bit
import util.machineProductCfg as MPC import util.machineProductCfg as MPC
import records.lfRecord as LFR import util.lfRecord as LFR
import gzip import gzip
from os import remove from os import remove
import xml.dom.minidom import xml.dom.minidom

View File

@@ -1,6 +1,6 @@
import asyncio import asyncio
from recordGenerators import alerts,currentObservations,hourlyForecast,dailyForecast, airQuality, airportDelays, achesAndPains, breathing, heatingAndCooling, mosquitoActivity, pollenForecast, tideForecast, wateringNeeds from recordGenerators import alerts,currentObservations,hourlyForecast,dailyForecast, airQuality, airportDelays, achesAndPains, breathing, heatingAndCooling, mosquitoActivity, pollenForecast, tideForecast, wateringNeeds
from radar import TWCRadarCollector from radar import radarCollector
from datetime import datetime from datetime import datetime
@@ -10,7 +10,7 @@ async def updateMosaicTask():
while True: while True:
# Mosaic intervals are 5+1 minutes, so instead of waiting 40 seconds and running "Datetime.now()" twice, We run it once and wait for 60. # Mosaic intervals are 5+1 minutes, so instead of waiting 40 seconds and running "Datetime.now()" twice, We run it once and wait for 60.
if datetime.now().minute in mosaicUpdateIntervals: if datetime.now().minute in mosaicUpdateIntervals:
await TWCRadarCollector.collect("radarmosaic") await radarCollector.collect("radarmosaic")
await asyncio.sleep(1) await asyncio.sleep(1)
async def updateSatradTask(): async def updateSatradTask():
@@ -19,7 +19,7 @@ async def updateSatradTask():
while True: while True:
#Satrad intervals are 10+1 minutes, so instead of waiting 40 seconds and running "Datetime.now()" twice, We run it once and wait for 60. #Satrad intervals are 10+1 minutes, so instead of waiting 40 seconds and running "Datetime.now()" twice, We run it once and wait for 60.
if datetime.now().minute in satradUpdateIntervals: if datetime.now().minute in satradUpdateIntervals:
await TWCRadarCollector.collect("satrad") await radarCollector.collect("satrad")
await asyncio.sleep(1) await asyncio.sleep(1)

View File

@@ -0,0 +1 @@
# This file makes it to where the sys.path.append tomfoolery doesn't have to exist

View File

@@ -22,8 +22,10 @@ BUF_SIZE = 1396
MULTICAST_TTL = 2 MULTICAST_TTL = 2
conn = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) conn = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
conn.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,socket.inet_aton(MCAST_GRP)+socket.inet_aton(MCAST_IF)) conn.bind((MCAST_IF, 63216))
# The below multicast socket options to bind to an interface/add a membership doesn't work on Linux systems.
# conn.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,socket.inet_aton(MCAST_GRP)+socket.inet_aton(MCAST_IF))
test = b"This is a test" test = b"This is a test"
@@ -147,6 +149,7 @@ def sendCommand(command, Pri, msgNum = None):
with open(msg_id_file, "r") as f: with open(msg_id_file, "r") as f:
oMsgId = f.read() oMsgId = f.read()
msgNum = int(oMsgId) msgNum = int(oMsgId)
l.debug(f"Got message ID {msgNum}")
f.close() f.close()
nMsgNum = msgNum + 1 nMsgNum = msgNum + 1

View File

@@ -1,7 +1,7 @@
import sqlite3 import sqlite3
# Make a connection to the LFRecord database # Make a connection to the LFRecord database
con = sqlite3.connect("records/LFRecord.db") con = sqlite3.connect("util/LFRecord.db")
cur = con.cursor() cur = con.cursor()