philseeley / boatinstrument

Boat Instrument
GNU General Public License v3.0
3 stars 1 forks source link

Derived data #9

Closed mgrouch closed 2 days ago

mgrouch commented 1 month ago

Hello :)

I've done similar instrument display but on esp32. The code is here: https://github.com/bareboat-necessities/bbn-m5stack-tough It might give you some ideas as well. There are some example screenshots.

One of the features is derived data. It calculates magnetic variation based on time and location and can translate magnetic to true and vice versa. Also it calculates sunrise and sunset based on location and date.

True wind calculations can also be done if there is enough data.

There is central storage of all boat data with age of each updated parameter in memory. You might be able to re-use some code or ideas.

https://github.com/bareboat-necessities/bbn-m5stack-tough/blob/main/bbn_m5tough_active_boat/ship_data_model.h

Also there is another project

https://github.com/pypilot/pypilot_mfd

It has AIS screens.

I hope this is helpful.

Thanks a lot!

mgrouch commented 1 month ago

There are some C to dart conversion tools.

Ex: https://www.codeconvert.ai/c-to-dart-converter

might come handy

mgrouch commented 1 month ago

Example for result of C to dart conversion:

enum OnOffE {
  NA(-1),
  OFF(0),
  ON(1);

  final int value;
  const OnOffE(this.value);
}

enum NotificationSeverityE {
  SEVERITY_NA(-1),
  ALARM(0),
  ALERT(1),
  WARN(2),
  EMERGENCY(3);

  final int value;
  const NotificationSeverityE(this.value);
}

enum ApModeE {
  MODE_NA(-1),
  HEADING_MAG(0),
  HEADING_TRUE(1),
  APP_WIND(2),
  APP_WIND_MAG(3),
  APP_WIND_TRUE(4),
  TRUE_WIND(5),
  TRUE_WIND_MAG(6),
  TRUE_WIND_TRUE(7),
  GROUND_WIND_MAG(8),
  GROUND_WIND_TRUE(9),
  COG_MAG(10),
  COG_TRUE(11),
  NAV(12);

  final int value;
  const ApModeE(this.value);
}

enum ApStateE {
  STATE_NA(-1),
  STANDBY(0),
  ENGAGED(1);

  final int value;
  const ApStateE(this.value);
}

enum ApCmdTypeE {
  CMD_TYPE_NA(-1),
  FOLLOW_DIR(0),
  FOLLOW_ROUTE(1);

  final int value;
  const ApCmdTypeE(this.value);
}

typedef AgeT = int;

class OnOffT {
  OnOffE st;
  AgeT age;

  OnOffT(this.st, [this.age = 0]);
}

class ApModeT {
  ApModeE mode;
  AgeT age;

  ApModeT(this.mode, [this.age = 0]);
}

class ApCmdTypeT {
  ApCmdTypeE cmd;
  AgeT age;

  ApCmdTypeT(this.cmd, [this.age = 0]);
}

class ApStateT {
  ApStateE st;
  AgeT age;

  ApStateT(this.st, [this.age = 0]);
}

class AngleDegT {
  double deg;
  AgeT age;

  AngleDegT([this.deg = 0, this.age = 0]);
}

class HourFloatT {
  double hr;
  AgeT age;

  HourFloatT(this.hr, [this.age = 0]);
}

class KnT {
  double kn;
  AgeT age;

  KnT([this.kn = 0, this.age = 0]);
}

class LengthMT {
  double m;
  AgeT age;

  LengthMT([this.m = 0, this.age = 0]);
}

class RPMT {
  double rpm;
  AgeT age;

  RPMT([this.rpm = 0, this.age = 0]);
}

class TimeTmT {}

class EnvTimeT {
  TimeTmT t;
  AgeT age;

  EnvTimeT(this.t, [this.age = 0]);
}

class NavLight {
  OnOffT state;
  AgeT age;

  NavLight(this.state, [this.age = 0]);
}

class AngularVelocityT {
  double degMin;
  AgeT age;

  AngularVelocityT([this.degMin = 0, this.age = 0]);
}

class PositionT {
  AngleDegT lat;
  AngleDegT lon;

  PositionT(this.lat, this.lon);
}

class AttitudeT {
  AngleDegT heel;
  AngleDegT pitch;

  AttitudeT(this.heel, this.pitch);
}

class NavLightsT {
  NavLight anchor;
  NavLight motoring;
  NavLight stern;
  NavLight bowRedGreen;

  NavLightsT(this.anchor, this.motoring, this.stern, this.bowRedGreen);
}

class NextPointT {
  AngleDegT bearingTrue;
  AngleDegT bearingMag;
  LengthMT distance;
  KnT velocityMadeGood;

  NextPointT(this.bearingTrue, this.bearingMag, this.distance, this.velocityMadeGood);
}

class CourseRhumblineT {
  LengthMT crossTrackError;
  AngleDegT bearingTrackTrue;
  AngleDegT bearingTrackMag;
  NextPointT nextPoint;

  CourseRhumblineT(this.crossTrackError, this.bearingTrackTrue, this.bearingTrackMag, this.nextPoint);
}

enum NavStateE {
  NS_NA(-1),
  NS_MOORED(0),
  NS_MOTORING(1),
  NS_SAILING(2),
  NS_ANCHORED(3);

  final int value;
  const NavStateE(this.value);
}

class NavStateT {
  NavStateE st;
  AgeT age;

  NavStateT([this.st = NavStateE.NS_NA, this.age = 0]);
}

class NavigationT {
  NavStateT state;
  PositionT position;
  PositionT positionBefore;
  AttitudeT attitude;
  AngleDegT courseOverGroundTrue;
  AngleDegT courseOverGroundMag;
  AngleDegT magVar;
  AngleDegT headingMag;
  AngleDegT headingTrue;
  AngleDegT leeway;
  AngularVelocityT rateOfTurn;
  KnT speedOverGround;
  KnT speedOverGroundAvg;
  KnT speedThroughWater;
  KnT drift;
  AngleDegT setTrue;
  NavLightsT lights;
  CourseRhumblineT courseRhumbline;

  NavigationT(this.state, this.position, this.positionBefore, this.attitude, this.courseOverGroundTrue, this.courseOverGroundMag, this.magVar, this.headingMag, this.headingTrue, this.leeway, this.rateOfTurn, this.speedOverGround, this.speedOverGroundAvg, this.speedThroughWater, this.drift, this.setTrue, this.lights, this.courseRhumbline);
}

class WindT {
  KnT apparentWindSpeed;
  AngleDegT apparentWindAngle;
  AngleDegT apparentWindDirTrue;
  AngleDegT apparentWindDirMag;
  KnT trueWindSpeed;
  AngleDegT trueWindAngle;

  WindT(this.apparentWindSpeed, this.apparentWindAngle, this.apparentWindDirTrue, this.apparentWindDirMag, this.trueWindSpeed, this.trueWindAngle);
}
mgrouch commented 1 month ago

Even cooler. I asked AI 'remove T suffix for names of types'

then it made:

enum OnOff {
  NA(-1),
  OFF(0),
  ON(1);

  final int value;
  const OnOff(this.value);
}

enum NotificationSeverity {
  SEVERITY_NA(-1),
  ALARM(0),
  ALERT(1),
  WARN(2),
  EMERGENCY(3);

  final int value;
  const NotificationSeverity(this.value);
}

enum ApMode {
  MODE_NA(-1),
  HEADING_MAG(0),
  HEADING_TRUE(1),
  APP_WIND(2),
  APP_WIND_MAG(3),
  APP_WIND_TRUE(4),
  TRUE_WIND(5),
  TRUE_WIND_MAG(6),
  TRUE_WIND_TRUE(7),
  GROUND_WIND_MAG(8),
  GROUND_WIND_TRUE(9),
  COG_MAG(10),
  COG_TRUE(11),
  NAV(12);

  final int value;
  const ApMode(this.value);
}

enum ApState {
  STATE_NA(-1),
  STANDBY(0),
  ENGAGED(1);

  final int value;
  const ApState(this.value);
}

enum ApCmdType {
  CMD_TYPE_NA(-1),
  FOLLOW_DIR(0),
  FOLLOW_ROUTE(1);

  final int value;
  const ApCmdType(this.value);
}

typedef Age = int;

class OnOffStruct {
  OnOff st;
  Age age;

  OnOffStruct(this.st, [this.age = 0]);
}

class ApModeStruct {
  ApMode mode;
  Age age;

  ApModeStruct(this.mode, [this.age = 0]);
}

class ApCmdTypeStruct {
  ApCmdType cmd;
  Age age;

  ApCmdTypeStruct(this.cmd, [this.age = 0]);
}

class ApStateStruct {
  ApState st;
  Age age;

  ApStateStruct(this.st, [this.age = 0]);
}

class AngleDeg {
  double deg;
  Age age;

  AngleDeg([this.deg = 0, this.age = 0]);
}

class HourFloat {
  double hr;
  Age age;

  HourFloat(this.hr, [this.age = 0]);
}

class Kn {
  double kn;
  Age age;

  Kn([this.kn = 0, this.age = 0]);
}

class LengthM {
  double m;
  Age age;

  LengthM([this.m = 0, this.age = 0]);
}

class RPM {
  double rpm;
  Age age;

  RPM([this.rpm = 0, this.age = 0]);
}

class EnvTime {
  DateTime t;
  Age age;

  EnvTime(this.t, [this.age = 0]);
}

class NavLight {
  OnOffStruct state;
  Age age;

  NavLight(this.state, [this.age = 0]);
}

class AngularVelocity {
  double degMin;
  Age age;

  AngularVelocity([this.degMin = 0, this.age = 0]);
}

class Position {
  AngleDeg lat;
  AngleDeg lon;

  Position(this.lat, this.lon);
}

class Attitude {
  AngleDeg heel;
  AngleDeg pitch;

  Attitude(this.heel, this.pitch);
}

class NavLights {
  NavLight anchor;
  NavLight motoring;
  NavLight stern;
  NavLight bowRedGreen;

  NavLights(this.anchor, this.motoring, this.stern, this.bowRedGreen);
}

class NextPoint {
  AngleDeg bearingTrue;
  AngleDeg bearingMag;
  LengthM distance;
  Kn velocityMadeGood;

  NextPoint(this.bearingTrue, this.bearingMag, this.distance, this.velocityMadeGood);
}

class CourseRhumbline {
  LengthM crossTrackError;
  AngleDeg bearingTrackTrue;
  AngleDeg bearingTrackMag;
  NextPoint nextPoint;

  CourseRhumbline(this.crossTrackError, this.bearingTrackTrue, this.bearingTrackMag, this.nextPoint);
}

enum NavState {
  NS_NA(-1),
  NS_MOORED(0),
  NS_MOTORING(1),
  NS_SAILING(2),
  NS_ANCHORED(3);

  final int value;
  const NavState(this.value);
}

class NavStateStruct {
  NavState st;
  Age age;

  NavStateStruct([this.st = NavState.NS_NA, this.age = 0]);
}

class Navigation {
  NavStateStruct state;
  Position position;
  Position positionBefore;
  Attitude attitude;
  AngleDeg courseOverGroundTrue;
  AngleDeg courseOverGroundMag;
  AngleDeg magVar;
  AngleDeg headingMag;
  AngleDeg headingTrue;
  AngleDeg leeway;
  AngularVelocity rateOfTurn;
  Kn speedOverGround;
  Kn speedOverGroundAvg;
  Kn speedThroughWater;
  Kn drift;
  AngleDeg setTrue;
  NavLights lights;
  CourseRhumbline courseRhumbline;

  Navigation(this.state, this.position, this.positionBefore, this.attitude, this.courseOverGroundTrue, this.courseOverGroundMag, this.magVar, this.headingMag, this.headingTrue, this.leeway, this.rateOfTurn, this.speedOverGround, this.speedOverGroundAvg, this.speedThroughWater, this.drift, this.setTrue, this.lights, this.courseRhumbline);
}

class Wind {
  Kn apparentWindSpeed;
  AngleDeg apparentWindAngle;
  AngleDeg apparentWindDirTrue;
  AngleDeg apparentWindDirMag;
  Kn trueWindSpeed;
  AngleDeg trueWindAngle;

  Wind(this.apparentWindSpeed, this.apparentWindAngle, this.apparentWindDirTrue, this.apparentWindDirMag, this.trueWindSpeed, this.trueWindAngle);
}
mgrouch commented 1 month ago

Here is AI translated code for Sunrise/Sunset calculations:

import 'dart:math';

int daysSince2000Jan0(int y, int m, int d) {
  return (367 * y - (7 * (y + ((m + 9) ~/ 12)) ~/ 4) + (275 * m ~/ 9) + d - 730530);
}

const double PI = 3.1415926535897932384;
const double RADEG = (180.0 / PI);
const double DEGRAD = (PI / 180.0);
double sind(double x) => sin(x * DEGRAD);
double cosd(double x) => cos(x * DEGRAD);
double tand(double x) => tan(x * DEGRAD);
double atand(double x) => (RADEG * atan(x));
double asind(double x) => (RADEG * asin(x));
double acosd(double x) => (RADEG * acos(x));
double atan2d(double y, double x) => (RADEG * atan2(y, x));
double dayLength(int year, int month, int day, double lon, double lat) => daylen(year, month, day, lon, lat, -35.0 / 60.0, 1);
double dayCivilTwilightLength(int year, int month, int day, double lon, double lat) => daylen(year, month, day, lon, lat, -6.0, 0);
double dayNauticalTwilightLength(int year, int month, int day, double lon, double lat) => daylen(year, month, day, lon, lat, -12.0, 0);
double dayAstronomicalTwilightLength(int year, int month, int day, double lon, double lat) => daylen(year, month, day, lon, lat, -18.0, 0);
void sunRiseSet(int year, int month, int day, double lon, double lat, List<double> rise, List<double> set) => sunriset(year, month, day, lon, lat, -35.0 / 60.0, 1, rise, set);
void civilTwilight(int year, int month, int day, double lon, double lat, List<double> start, List<double> end) => sunriset(year, month, day, lon, lat, -6.0, 0, start, end);
void nauticalTwilight(int year, int month, int day, double lon, double lat, List<double> start, List<double> end) => sunriset(year, month, day, lon, lat, -12.0, 0, start, end);
void astronomicalTwilight(int year, int month, int day, double lon, double lat, List<double> start, List<double> end) => sunriset(year, month, day, lon, lat, -18.0, 0, start, end);

int sunriset(int year, int month, int day, double lon, double lat, double altit, int upperLimb, List<double> trise, List<double> tset) {
  double d, sr, sRA, sdec, sradius, t, tsouth, sidtime;
  int rc = 0;
  d = daysSince2000Jan0(year, month, day) + 0.5 - lon / 360.0;
  sidtime = revolution(GMST0(d) + 180.0 + lon);
  sunRAdec(d, &sRA, &sdec, &sr);
  tsouth = 12.0 - rev180(sidtime - sRA) / 15.0;
  sradius = 0.2666 / sr;
  if (upperLimb == 1) altit -= sradius;
  {
    double cost;
    cost = (sind(altit) - sind(lat) * sind(sdec)) / (cosd(lat) * cosd(sdec));
    if (cost >= 1.0)
      rc = -1, t = 0.0;
    else if (cost <= -1.0)
      rc = +1, t = 12.0;
    else
      t = acosd(cost) / 15.0;
  }
  trise[0] = tsouth - t;
  tset[0] = tsouth + t;
  return rc;
}

double daylen(int year, int month, int day, double lon, double lat, double altit, int upperLimb) {
  double d, oblEcl, sr, slon, sinSdecl, cosSdecl, sradius, t;
  d = daysSince2000Jan0(year, month, day) + 0.5 - lon / 360.0;
  oblEcl = 23.4393 - 3.563E-7 * d;
  sunpos(d, &slon, &sr);
  sinSdecl = sind(oblEcl) * sind(slon);
  cosSdecl = sqrt(1.0 - sinSdecl * sinSdecl);
  sradius = 0.2666 / sr;
  if (upperLimb == 1) altit -= sradius;
  {
    double cost;
    cost = (sind(altit) - sind(lat) * sinSdecl) / (cosd(lat) * cosSdecl);
    if (cost >= 1.0)
      t = 0.0;
    else if (cost <= -1.0)
      t = 24.0;
    else
      t = (2.0 / 15.0) * acosd(cost);
  }
  return t;
}

void sunpos(double d, double* lon, double* r) {
  double M, w, e, E, x, y, v;
  M = revolution(356.0470 + 0.9856002585 * d);
  w = 282.9404 + 4.70935E-5 * d;
  e = 0.016709 - 1.151E-9 * d;
  E = M + e * RADEG * sind(M) * (1.0 + e * cosd(M));
  x = cosd(E) - e;
  y = sqrt(1.0 - e * e) * sind(E);
  *r = sqrt(x * x + y * y);
  v = atan2d(y, x);
  *lon = v + w;
  if (*lon >= 360.0) *lon -= 360.0;
}

void sunRAdec(double d, double* RA, double* dec, double* r) {
  double lon, oblEcl, x, y, z;
  sunpos(d, &lon, r);
  x = *r * cosd(lon);
  y = *r * sind(lon);
  oblEcl = 23.4393 - 3.563E-7 * d;
  z = y * sind(oblEcl);
  y = y * cosd(oblEcl);
  *RA = atan2d(y, x);
  *dec = atan2d(z, sqrt(x * x + y * y));
}

const double INV360 = (1.0 / 360.0);

double revolution(double x) {
  return (x - 360.0 * (x * INV360).floor());
}

double rev180(double x) {
  return (x - 360.0 * (x * INV360 + 0.5).floor());
}

double GMST0(double d) {
  double sidtim0;
  sidtim0 = revolution((180.0 + 356.0470 + 282.9404) + (0.9856002585 + 4.70935E-5) * d);
  return sidtim0;
}

From this C code:

https://raw.githubusercontent.com/bareboat-necessities/bbn-m5stack-tough/main/bbn_m5tough_active_boat/sunriset.h

mgrouch commented 1 month ago

Here is whole data model translated into dart

enum OnOff {
  NA = -1,
  OFF = 0,
  ON = 1
}

enum NotificationSeverity {
  SEVERITY_NA = -1,
  ALARM = 0,
  ALERT = 1,
  WARN = 2,
  EMERGENCY = 3
}

enum ApMode {
  MODE_NA = -1,
  HEADING_MAG = 0,
  HEADING_TRUE = 1,
  APP_WIND = 2,
  APP_WIND_MAG = 3,
  APP_WIND_TRUE = 4,
  TRUE_WIND = 5,
  TRUE_WIND_MAG = 6,
  TRUE_WIND_TRUE = 7,
  GROUND_WIND_MAG = 8,
  GROUND_WIND_TRUE = 9,
  COG_MAG = 10,
  COG_TRUE = 11,
  NAV = 12,
}

enum ApState {
  STATE_NA = -1,
  STANDBY = 0,
  ENGAGED = 1
}

enum ApCmdType {
  CMD_TYPE_NA = -1,
  FOLLOW_DIR = 0,
  FOLLOW_ROUTE = 1
}

typedef int age_t;

class OnOffT {
  OnOff st;
  age_t age = 0;
}

class ApModeT {
  ApMode mode;
  age_t age = 0;
}

class ApCmdTypeT {
  ApCmdType cmd;
  age_t age = 0;
}

class ApStateT {
  ApState st;
  age_t age = 0;
}

class AngleDegT {
  double deg = 0;
  age_t age = 0;
}

class HourFloatT {
  double hr;
  age_t age = 0;
}

class KnT {
  double kn = 0;
  age_t age = 0;
}

class LengthMT {
  double m = 0;
  age_t age = 0;
}

class RPMT {
  double rpm = 0;
  age_t age = 0;
}

typedef DateTime TimeTmT;

class EnvTimeT {
  TimeTmT t;
  age_t age = 0;
}

class NavLight {
  OnOffT state;
  age_t age = 0;
}

class AngularVelocityT {
  double degMin = 0;
  age_t age = 0;
}

class PositionT {
  AngleDegT lat;
  AngleDegT lon;
}

class AttitudeT {
  AngleDegT heel;
  AngleDegT pitch;
}

class NavLightsT {
  NavLight anchor;
  NavLight motoring;
  NavLight stern;
  NavLight bowRedGreen;
}

class NextPointT {
  AngleDegT bearingTrue;
  AngleDegT bearingMag;
  LengthMT distance;
  KnT velocityMadeGood;
}

class CourseRhumblineT {
  LengthMT crossTrackError;
  AngleDegT bearingTrackTrue;
  AngleDegT bearingTrackMag;
  NextPointT nextPoint;
}

enum NavState {
  NS_NA = -1,
  NS_MOORED = 0,
  NS_MOTORING = 1,
  NS_SAILING = 2,
  NS_ANCHORED = 3,
}

class NavStateT {
  NavState st = NavState.NS_NA;
  age_t age = 0;
}

class NavigationT {
  NavStateT state;
  PositionT position;
  PositionT positionBefore;
  AttitudeT attitude;
  AngleDegT courseOverGroundTrue;
  AngleDegT courseOverGroundMag;
  AngleDegT magVar;
  AngleDegT headingMag;
  AngleDegT headingTrue;
  AngleDegT leeway;
  AngularVelocityT rateOfTurn;
  KnT speedOverGround;
  KnT speedOverGroundAvg;
  KnT speedThroughWater;
  KnT drift;
  AngleDegT setTrue;
  NavLightsT lights;
  CourseRhumblineT courseRhumbline;
}

class WindT {
  KnT apparentWindSpeed;
  AngleDegT apparentWindAngle;
  AngleDegT apparentWindDirTrue;
  AngleDegT apparentWindDirMag;
  KnT trueWindSpeed;
  AngleDegT trueWindAngle;
  AngleDegT trueWindDirTrue;
  AngleDegT trueWindDirMag;
  KnT groundWindSpeed;
  AngleDegT groundWindAngle;
  AngleDegT groundWindDirTrue;
  AngleDegT groundWindDirMag;
}

class DepthT {
  LengthMT belowKeel;
  LengthMT belowTransducer;
  LengthMT belowSurface;
}

class DegCT {
  double degC;
  age_t age = 0;
}

class HPaT {
  double hPa;
  age_t age = 0;
}

class PercentT {
  double pct;
  age_t age = 0;
}

class LuxT {
  double lux;
  age_t age = 0;
}

class LittersT {
  double L;
  age_t age = 0;
}

class WaterT {
  DegCT tempDegC;
  PercentT salinityPct;
}

class AirT {
  DegCT tempDegC;
  HPaT pressure;
  PercentT humidityPct;
  LuxT illuminance;
}

class EnvInsideT {
  AirT fridge;
  AirT freezer;
  AirT engineRoom;
  AirT salon;
  DegCT hotWater;
}

class EnvironmentT {
  EnvTimeT timeGps;
  EnvTimeT timeNet;
  WindT wind;
  DepthT depth;
  DepthT depthBefore;
  AngleDegT depthGradient;
  WaterT water;
  AirT airOutside;
  EnvInsideT envInside;
  HourFloatT sunrise;
  HourFloatT sunset;
  int noSunsetFlag = 0;
  int noDarkFlag = 0;
  HourFloatT daylightDuration;
  HourFloatT nauticalTwilightDuration;
  HourFloatT nauticalTwilightStart;
  HourFloatT nauticalTwilightEnd;
}

class CurrentAmpT {
  double amp;
  age_t age = 0;
}

class AmpHrT {
  double ampHr;
  age_t age = 0;
}

class VoltageVT {
  double volt;
  age_t age = 0;
}

class PowerWT {
  double watt;
  age_t age = 0;
}

class FreqHzT {
  double Hz;
  age_t age = 0;
}

class PowerNCurrentT {
  CurrentAmpT current;
  PowerWT powerW;
}

class SysAcT {
  PowerNCurrentT activeIn[3];
  PowerNCurrentT consumption[3];
}

class BatteryStatT {
  VoltageVT voltage;
  CurrentAmpT current;
  PowerWT powerW;
  PercentT stateOfChargePct;
}

class PvStatT {
  CurrentAmpT current;
  PowerWT powerW;
}

class SysDcT {
  PvStatT pv;
  BatteryStatT battery;
}

class ElectricalT {
  SysAcT sysAc;
  SysDcT sysDc;
}

class ApServoT {
  VoltageVT voltage;
  DegCT controllerTemp;
  AmpHrT ampHr;
}

class AutopilotT {
  ApStateT apState;
  AngleDegT heading;
  AngleDegT command;
  ApCmdTypeT commandType;
  ApModeT apMode;
  ApServoT apServo;
}

class SteeringT {
  AngleDegT rudderAngle;
  AutopilotT autopilot;
}

enum FluidType {
  FLUID_TYPE_NA = -1,
  FUEL = 0,
  FRESH_WATER = 1,
  WASTE_WATER = 2,
  LIVE_WELL = 3,
  LUBRICATION = 4,
  BLACK_WATER = 5,
  GAS = 64,
}

class TankT {
  FluidType fluidType = FluidType.FLUID_TYPE_NA;
  LittersT volume;
  PercentT percentOfFull;
}

const int MAX_TANKS = 8;

class TanksT {
  TankT tank[MAX_TANKS];
}

const int MAX_ENGINES = 8;
const int MAX_ENGINE_LBL_LENGTH = 32;

class EngineT {
  DegCT tempDegC;
  RPMT revolutionsRPM;
  DegCT oilTemp;
  HPaT oilPressure;
  DegCT coolantTemp;
  HPaT coolantPressure;
  VoltageVT alternatorVoltage;
  String engineLabel = '';
}

class PropulsionT {
  EngineT engines[MAX_ENGINES];
}

class NotificationT {
  NotificationSeverity severity;
  String message;
  age_t age = 0;
}

class NotificationsT {
  NotificationT lastNotification;
}

class DesignT {
  LengthMT length;
  LengthMT beam;
  LengthMT draft;
  LengthMT airHeight;
}

class VesselT {
  String name = '';
  String callSign = '';
  String mmsi = '';
}

class ShipDataT {
  NavigationT navigation;
  EnvironmentT environment;
  ElectricalT electrical;
  PropulsionT propulsion;
  SteeringT steering;
  TanksT tanks;
  DesignT design;
  VesselT vessel;
  NotificationsT notification;
}

With https://syntha.ai/converters/cpp-to-dart Unfortunately I couldn't give it a hint to drop 'T' suffixes

mgrouch commented 1 month ago

With removed 'T' suffixes

enum OnOff {
  NA = -1,
  OFF = 0,
  ON = 1
}

enum NotificationSeverity {
  SEVERITY_NA = -1,
  ALARM = 0,
  ALERT = 1,
  WARN = 2,
  EMERGENCY = 3
}

enum ApMode {
  MODE_NA = -1,
  HEADING_MAG = 0,
  HEADING_TRUE = 1,
  APP_WIND = 2,
  APP_WIND_MAG = 3,
  APP_WIND_TRUE = 4,
  TRUE_WIND = 5,
  TRUE_WIND_MAG = 6,
  TRUE_WIND_TRUE = 7,
  GROUND_WIND_MAG = 8,
  GROUND_WIND_TRUE = 9,
  COG_MAG = 10,
  COG_TRUE = 11,
  NAV = 12,
}

enum ApState {
  STATE_NA = -1,
  STANDBY = 0,
  ENGAGED = 1
}

enum ApCmdType {
  CMD_TYPE_NA = -1,
  FOLLOW_DIR = 0,
  FOLLOW_ROUTE = 1
}

typedef int age_t;

class OnOff{
  OnOff st;
  age_t age = 0;
}

class ApMode{
  ApMode mode;
  age_t age = 0;
}

class ApCmdType{
  ApCmdType cmd;
  age_t age = 0;
}

class ApState{
  ApState st;
  age_t age = 0;
}

class AngleDeg{
  double deg = 0;
  age_t age = 0;
}

class HourFloat{
  double hr;
  age_t age = 0;
}

class Kn{
  double kn = 0;
  age_t age = 0;
}

class LengthM{
  double m = 0;
  age_t age = 0;
}

class RPM{
  double rpm = 0;
  age_t age = 0;
}

typedef DateTime TimeTmT;

class EnvTime{
  TimeTmt;
  age_t age = 0;
}

class NavLight {
  OnOffstate;
  age_t age = 0;
}

class AngularVelocity{
  double degMin = 0;
  age_t age = 0;
}

class Position{
  AngleDeglat;
  AngleDeglon;
}

class Attitude{
  AngleDegheel;
  AngleDegpitch;
}

class NavLights{
  NavLight anchor;
  NavLight motoring;
  NavLight stern;
  NavLight bowRedGreen;
}

class NextPoint{
  AngleDegbearingTrue;
  AngleDegbearingMag;
  LengthMdistance;
  KnvelocityMadeGood;
}

class CourseRhumbline{
  LengthMcrossTrackError;
  AngleDegbearingTrackTrue;
  AngleDegbearingTrackMag;
  NextPointnextPoint;
}

enum NavState {
  NS_NA = -1,
  NS_MOORED = 0,
  NS_MOTORING = 1,
  NS_SAILING = 2,
  NS_ANCHORED = 3,
}

class NavState{
  NavState st = NavState.NS_NA;
  age_t age = 0;
}

class Navigation{
  NavStatestate;
  Positionposition;
  PositionpositionBefore;
  Attitudeattitude;
  AngleDegcourseOverGroundTrue;
  AngleDegcourseOverGroundMag;
  AngleDegmagVar;
  AngleDegheadingMag;
  AngleDegheadingTrue;
  AngleDegleeway;
  AngularVelocityrateOfTurn;
  KnspeedOverGround;
  KnspeedOverGroundAvg;
  KnspeedThroughWater;
  Kndrift;
  AngleDegsetTrue;
  NavLightslights;
  CourseRhumblinecourseRhumbline;
}

class Wind{
  KnapparentWindSpeed;
  AngleDegapparentWindAngle;
  AngleDegapparentWindDirTrue;
  AngleDegapparentWindDirMag;
  KntrueWindSpeed;
  AngleDegtrueWindAngle;
  AngleDegtrueWindDirTrue;
  AngleDegtrueWindDirMag;
  KngroundWindSpeed;
  AngleDeggroundWindAngle;
  AngleDeggroundWindDirTrue;
  AngleDeggroundWindDirMag;
}

class Depth{
  LengthMbelowKeel;
  LengthMbelowTransducer;
  LengthMbelowSurface;
}

class DegC{
  double degC;
  age_t age = 0;
}

class HPa{
  double hPa;
  age_t age = 0;
}

class Percent{
  double pct;
  age_t age = 0;
}

class Lux{
  double lux;
  age_t age = 0;
}

class Litters{
  double L;
  age_t age = 0;
}

class Water{
  DegCtempDegC;
  PercentsalinityPct;
}

class Air{
  DegCtempDegC;
  HPapressure;
  PercenthumidityPct;
  Luxilluminance;
}

class EnvInside{
  Airfridge;
  Airfreezer;
  AirengineRoom;
  Airsalon;
  DegChotWater;
}

class Environment{
  EnvTimetimeGps;
  EnvTimetimeNet;
  Windwind;
  Depthdepth;
  DepthdepthBefore;
  AngleDegdepthGradient;
  Waterwater;
  AirairOutside;
  EnvInsideenvInside;
  HourFloatsunrise;
  HourFloatsunset;
  int noSunsetFlag = 0;
  int noDarkFlag = 0;
  HourFloatdaylightDuration;
  HourFloatnauticalTwilightDuration;
  HourFloatnauticalTwilightStart;
  HourFloatnauticalTwilightEnd;
}

class CurrentAmp{
  double amp;
  age_t age = 0;
}

class AmpHr{
  double ampHr;
  age_t age = 0;
}

class VoltageV{
  double volt;
  age_t age = 0;
}

class PowerW{
  double watt;
  age_t age = 0;
}

class FreqHz{
  double Hz;
  age_t age = 0;
}

class PowerNCurrent{
  CurrentAmpcurrent;
  PowerWpowerW;
}

class SysAc{
  PowerNCurrentactiveIn[3];
  PowerNCurrentconsumption[3];
}

class BatteryStat{
  VoltageVvoltage;
  CurrentAmpcurrent;
  PowerWpowerW;
  PercentstateOfChargePct;
}

class PvStat{
  CurrentAmpcurrent;
  PowerWpowerW;
}

class SysDc{
  PvStatpv;
  BatteryStatbattery;
}

class Electrical{
  SysAcsysAc;
  SysDcsysDc;
}

class ApServo{
  VoltageVvoltage;
  DegCcontrollerTemp;
  AmpHrampHr;
}

class Autopilot{
  ApStateapState;
  AngleDegheading;
  AngleDegcommand;
  ApCmdTypecommandType;
  ApModeapMode;
  ApServoapServo;
}

class Steering{
  AngleDegrudderAngle;
  Autopilotautopilot;
}

enum FluidType {
  FLUID_TYPE_NA = -1,
  FUEL = 0,
  FRESH_WATER = 1,
  WASTE_WATER = 2,
  LIVE_WELL = 3,
  LUBRICATION = 4,
  BLACK_WATER = 5,
  GAS = 64,
}

class Tank{
  FluidType fluidType = FluidType.FLUID_TYPE_NA;
  Littersvolume;
  PercentpercentOfFull;
}

const int MAX_TANKS = 8;

class Tanks{
  Tanktank[MAX_TANKS];
}

const int MAX_ENGINES = 8;
const int MAX_ENGINE_LBL_LENGTH = 32;

class Engine{
  DegCtempDegC;
  RPMrevolutionsRPM;
  DegCoilTemp;
  HPaoilPressure;
  DegCcoolantTemp;
  HPacoolantPressure;
  VoltageValternatorVoltage;
  String engineLabel = '';
}

class Propulsion{
  Engineengines[MAX_ENGINES];
}

class Notification{
  NotificationSeverity severity;
  String message;
  age_t age = 0;
}

class Notifications{
  NotificationlastNotification;
}

class Design{
  LengthMlength;
  LengthMbeam;
  LengthMdraft;
  LengthMairHeight;
}

class Vessel{
  String name = '';
  String callSign = '';
  String mmsi = '';
}

class ShipData{
  Navigationnavigation;
  Environmentenvironment;
  Electricalelectrical;
  Propulsionpropulsion;
  Steeringsteering;
  Tankstanks;
  Designdesign;
  Vesselvessel;
  Notificationsnotification;
}
mgrouch commented 1 month ago

For magnetic variation there is already Dart library

https://pub.dev/documentation/geomag/latest/geomag/GeoMag-class.html

Thanks

philseeley commented 1 month ago

@mgrouch wow, that's great work with the code translation. I'll make a note of that for possible future use.

As for the derived data, I've had a look at the signalk-derived-data plugin and it covers a lot, including true-wind and sunrise/sunset times etc. So at this point I'd be focusing on creating Boxes for the generated signalk paths.

philseeley commented 1 month ago

Added SunlightBox and bumped version.

mgrouch commented 1 month ago

Thank you!

philseeley commented 1 month ago

Added MoonBox and bumped version.