feat(sat): point the antenna — EasyComm II az/el rotator

EasyComm is what satellite rotator controllers agreed on, so a box that
works with SatPC32, Gpredict or Hamlib works here. Serial or TCP, and its
own settings rather than the HF rotator's: an az/el pair is a different
machine on a different port, and an operator who has both must not have
to choose.

A great many EasyComm controllers — the Arduino trackers above all —
accept commands and never say a word back. That is legal and common, so a
silent controller is not treated as a broken one: it is still driven, and
the last commanded position is reported in its place, marked as commanded
rather than read. A stuck rotator must not be able to hide behind an
order it never carried out, which is why the panel shows the antenna's
position beside the satellite's.

The 450° overlap is the reason a satellite rotator is worth having, so it
is used: a pass crossing north continues past 360 instead of unwinding
three quarters of a turn with the antenna sweeping the ground. Below the
configured elevation the mast is left alone — the numbers are right all
the way round the orbit, but a rotator that chases a satellite through
the far side of the earth spends the night turning, and a mast has a
finite number of turns in it.
This commit is contained in:
2026-09-07 11:34:35 +02:00
parent 465481f8f1
commit 90e363f49e
11 changed files with 953 additions and 11 deletions
+28
View File
@@ -4082,6 +4082,16 @@ export namespace main {
auto_tle: boolean;
grid: string;
alt_m: number;
rot_on: boolean;
rot_transport: string;
rot_host: string;
rot_port: number;
rot_com: string;
rot_baud: number;
rot_max_az: number;
rot_min_el: number;
rot_step: number;
rot_park: boolean;
static createFrom(source: any = {}) {
return new SatSettings(source);
@@ -4095,6 +4105,16 @@ export namespace main {
this.auto_tle = source["auto_tle"];
this.grid = source["grid"];
this.alt_m = source["alt_m"];
this.rot_on = source["rot_on"];
this.rot_transport = source["rot_transport"];
this.rot_host = source["rot_host"];
this.rot_port = source["rot_port"];
this.rot_com = source["rot_com"];
this.rot_baud = source["rot_baud"];
this.rot_max_az = source["rot_max_az"];
this.rot_min_el = source["rot_min_el"];
this.rot_step = source["rot_step"];
this.rot_park = source["rot_park"];
}
}
export class SatTLEInfo {
@@ -4150,6 +4170,10 @@ export namespace main {
visible: boolean;
radio: string;
error: string;
rot_on: boolean;
rot_az: number;
rot_el: number;
rot_live: boolean;
static createFrom(source: any = {}) {
return new SatTrackStatus(source);
@@ -4170,6 +4194,10 @@ export namespace main {
this.visible = source["visible"];
this.radio = source["radio"];
this.error = source["error"];
this.rot_on = source["rot_on"];
this.rot_az = source["rot_az"];
this.rot_el = source["rot_el"];
this.rot_live = source["rot_live"];
}
}