Beacons¶
The beaconing system handles sending out Unnumbered Information frames at a specified interval. These can be used to handle things such as APRS updates, station identifiers, and custom telemetry. The beacon system comes pre-loaded with a station ID beacon that runs within 10 minutes of activity (other than other beacons.)
This can configured with the beacon key of the station's global configuration.
from pax25.station import Station
station = Station(config={
# ...
"beacon": {
# Enable the default 'ID beacon'. You might disable this if you want
# to use a more complex beacon function of your own making. Otherwise
# you should probably keep it enabled to meet legal requirements.
"id_beacon_enabled": True,
# Interval for which the ID beacon should transmit in the case we've
# made a recent transmission. Default is 600 seconds, AKA 10 minutes.
"id_beacon_interval": 600,
# The destination address for the ID beacon. This is set as 'ID' to
# make it obvious that this is a station ID.
"id_beacon_destination": "ID",
# List of digipeaters to use for the beacon. Specified by
# the name of the interfaces as the key, and the digipeater
# addresses as the value. By default, uses no digipeaters.
"id_beacon_digipeaters": {
"outbound": ["JIMBOB-3", "BORK"],
},
# A string representing the content of the beacon. If set to None,
# a message will automatically be generated based on your station name
# and installed applications. This string will be encoded to utf-8
# before it is sent.
"id_beacon_content": None,
}
# ...
})
Adding Beacons¶
Beacons can be added to the beacon service using the add_beacon method with a BeaconSettings object used to specify the beacon's configuration.
from datetime import datetime
from random import choice
from pax25.ax25.address import Address
from pax25.services.beacon import BeaconSettings
async def send_message(context):
"""
Return data for the beacon to send outward.
Context is a BeaconContext object which contains information
about this beacon, such as the last time it was run, and the
BeaconSettings used.
"""
if context.last_run is None:
# We must always return bytes, not strings.
return b"Hello! This is my first time running."
now = datetime.now()
# The weekday value starts at 0 with Monday and ends with 6 as
# Sunday.
if now.weekday() == 2:
# Which means...
return b"It is Wednesday, my dudes!"
elif now.weekday() == 5:
# We can also send custom messages per each interface.
# Here, we'll send a random message to each.
options = [
b"Thank God it's Friday!",
b"Clockin' out early!",
b"Hope you brought snacks."
]
messages = {}
for interface in context.station.interfaces.values():
# Interfaces which are omitted won't get a submission.
if not interface.gateway:
continue
messages[interface.name] = choice(options)
return messages
# If we return None, the last_run value is not updated, and no
# beacon is sent. Note that if you return an empty dict, it will
# still count the beacon as having 'run'. Only None preserves
# the old last_run value.
return None
# See the tutorial for setting up station objects. We'll assume one is defined here.
station.beacon.add_beacon(
# Beacons have unique labels which are used to remove them as needed.
"test_beacon",
BeaconSettings(
# Intervals are specified in the number of seconds between sending.
# This would send once every minute.
interval=60,
# Beacon functions must be an async function, AKA a 'coroutine'.
# Writing async code is outside the scope of this tutorial,
# but a working example function that doesn't utilize async features
# is provided above.
coroutine=send_message,
# Beacons must have a destination address. They may optionally have
# digipeaters as well. The destination address need not be an actual
# callsign. In this case we use 'BEACON' to make it obvious that
# this information is intended as beacon info.
dest=Address("BEACON"),
)
)
pax25.services.beacon
¶
Beacon service.
BeaconContext
dataclass
¶
Context for a beacon.
Source code in pax25/services/beacon.py
BeaconService
¶
Beacon service. Used for sending out beacons on regular intervals.
Beacons are sent out over all gateway interfaces.
Source code in pax25/services/beacon.py
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | |
settings: BeaconServiceSettings
property
¶
Return the beacon service's settings.
__init__(*, station: Station, settings: BeaconServiceSettings | None = None)
¶
Initialize the beacon service.
Source code in pax25/services/beacon.py
add_beacon(label: str, beacon_spec: BeaconSettings) -> BeaconTracker
¶
Adds a beacon for the service to track.
Source code in pax25/services/beacon.py
beacon_loop(label: str, beacon: BeaconTracker) -> None
async
¶
Creates a loop for a beacon.
This loop is configured to autocorrect for drift over time. Python won't give us true microsecond precision, but we can get close enough for any needs packet radio has. It might fail to correct if the interval is higher than we can reliably schedule recurring events, in which case this will just go as fast as it can.
Source code in pax25/services/beacon.py
clean_tasks() -> None
¶
reload_settings(settings: BeaconServiceSettings) -> None
async
¶
Reload the beacon settings.
Source code in pax25/services/beacon.py
remove_beacon(label: str) -> None
¶
Removes a beacon from the service.
Source code in pax25/services/beacon.py
resolve_beacon(label: str, future: Awaitable[BeaconContents]) -> None
async
¶
Performs a run of the given beacon.
Source code in pax25/services/beacon.py
run() -> None
¶
Initialization function. Starts the beacon service with the included station ID beacon.
Source code in pax25/services/beacon.py
BeaconSettings
dataclass
¶
Data structure for defining a beacon. This structure is mutable and updating it will update the beacon's settings.
Source code in pax25/services/beacon.py
BeaconTracker
dataclass
¶
Tracking object for beacons-- notes when their last run was, and holds their spec.
Source code in pax25/services/beacon.py
delta_to_microseconds(delta: timedelta) -> int
¶
generate_beacon_map(context: BeaconContext) -> PerInterfaceBytes
¶
Generate the default beacon text.
Source code in pax25/services/beacon.py
next_interval(last_timestamp: datetime, interval: int | float) -> datetime
async
¶
Return the value of the next minute, after waiting for it to arrive.
Source code in pax25/services/beacon.py
station_id_beacon(context: BeaconContext) -> BeaconContents
async
¶
Example beacon which sends its text if we've been transmitting for a while and haven't sent a station ID.