Example #1
0
    public void Start(Machinery machinery, DoorScheduler doorScheduler)
    {
      var config = new RestApiConfiguration();

      config.AddHandler("GET", "/sys/ping", "is server alive")
        .ReturnsNothing()
        .HandledBy(() => { });

      config.AddHandler("POST", "/sys/info", "get system state")
        .ReturnsJson()
        .HandledBy(() => HardwareInfo.Instance.GetSystemInfo());

      config.AddHandler("POST", "/sys/disk", "list content of filesystem")
        .ReturnsJson()
        .HandledBy(() => HardwareInfo.Instance.GetDiskInfo());

      config.AddHandler("GET", "/sys/network", "list network information")
        .ReturnsJson()
        .HandledBy(() => HardwareInfo.Instance.GetNetworkInterfaceInfo());

      config.AddHandler("GET", "/sys/time", "get current local time")
        .ReturnsJson()
        .HandledBy(() =>
        {
          var status = new JsonObject();
          status.Add("time", DateTime.Now);
          return status;
        });

      config.AddHandler("PUT", "/sys/time/{time}", "set current local time")
        .ReturnsNothing()
        .HandledBy((time) =>
        {
          // todo
          //Goke.ChickenHouse.HAL.Hardware.Instance.Clock.SetTime(
          var x = time.Length;
          throw new NotImplementedException("set time is not implemented yet");
        });

      config.AddHandler("POST", "/sys/time/sync", "sync time with NTP")
        .ReturnsJson()
        .HandledBy(() =>
        {
          RealTimeClock.Instance.UpdateFromNTP();
          var status = new JsonObject();
          status.Add("time", DateTime.Now);
          return status;
        });

      config.AddHandler("POST", "/sys/reboot", "reboot the device")
        .SetNotes("This will reboot the device and not return")
        .ReturnsNothing()
        .HandledBy(() => MainBoard.Reboot());


      config.AddHandler("GET", "/hw/doors/{doorname}", "get status for the door")
        .ReturnsJson()
        .HandledBy((doorname) =>
          {
            var door = machinery.LookupDoorByName(doorname);
            var status = new JsonObject();
            status.Add("name", door.Name);
            status.Add("status", EnumUtil.DoorStatusTostring(door.Status));
            return status;
          });

      config.AddHandler("POST", "/hw/doors/{doorname}/open", "open the door completely")
        .ReturnsNothing()
        .HandledBy((doorname) =>
          {
            var door = machinery.LookupDoorByName(doorname);
            machinery.Sequencer.Enqueue(() => door.OpenCompletely());
          });

      config.AddHandler("POST", "/hw/doors/{doorname}/close", "close the door completely")
        .ReturnsNothing()
        .HandledBy((doorname) =>
          {
            var door = machinery.LookupDoorByName(doorname);
            machinery.Sequencer.Enqueue(() => door.CloseCompletely());
          });

      config.AddHandler("POST", "/hw/doors/{doorname}/moveup/{millisec}", "move the door up")
        .ReturnsNothing()
        .HandledBy((doorname, millisec) =>
          {
            var door = machinery.LookupDoorByName(doorname);
            var msec = int.Parse(millisec);
            machinery.Sequencer.Enqueue(() => door.MoveUp(msec));
          });

      config.AddHandler("POST", "/hw/doors/{doorname}/movedown/{millisec}", "move the door down")
        .ReturnsNothing()
        .HandledBy((doorname, millisec) =>
          {
            var door = machinery.LookupDoorByName(doorname);
            var msec = int.Parse(millisec);
            machinery.Sequencer.Enqueue(() => door.MoveDown(msec));
          });

      config.AddHandler("POST", "/hw/doors/{doorname}/stop", "stop moving the door")
        .ReturnsNothing()
        .HandledBy((doorname) =>
          {
            var door = machinery.LookupDoorByName(doorname);
            door.StopMoving(); // Stop immediately - don't go through sequencer!
          });

      config.AddHandler("GET", "/hw/relays/{relayname}", "get state of relay")
        .ReturnsJson()
        .HandledBy((relayname) =>
          {
            var relay = machinery.LookupRelayByName(relayname);
            var status = new JsonObject();
            status.Add("name", relay.Name);
            status.Add("on", relay.On);
            return status;
          });

      config.AddHandler("PUT", "/hw/relays/{relayname}/on", "turn relay on")
        .ReturnsNothing()
        .HandledBy((relayname) =>
          {
            var relay = machinery.LookupRelayByName(relayname);
            relay.On = true;
          });

      config.AddHandler("PUT", "/hw/relays/{relayname}/off", "turn relay off")
        .ReturnsNothing()
        .HandledBy((relayname) =>
          {
            var relay = machinery.LookupRelayByName(relayname);
            relay.On = false;
          });

      config.AddHandler("POST", "/admin/log/clear", "clear the entire log")
        .ReturnsNothing()
        .HandledBy(() =>
          {
            Logger.Instance.Full.Clear();
            Logger.Instance.Errors.Clear();
          });

      config.AddHandler("GET", "/admin/log/full", "get full log")
        .ReturnsStream()
        .HandledBy((context) =>
          {
            context.Response.OutputStream.WriteByte((byte)'[');
            foreach (var line in Logger.Instance.Full.GetLines())
            {
              var b = System.Text.Encoding.UTF8.GetBytes(Json.NETMF.JsonSerializer.SerializeObject(line));
              context.Response.OutputStream.Write(b, 0, b.Length);
              context.Response.OutputStream.WriteByte((byte)',');
            }
            context.Response.OutputStream.WriteByte((byte)']');
          });

      config.AddHandler("GET", "/admin/log/errors", "get error log")
        .ReturnsJson()
        .HandledBy(() =>
          {
            return Logger.Instance.Errors.GetLinesAsJson();
          });

      config.AddHandler("GET", "/config/schedule", "get the schedule")
        .ReturnsJson()
        .HandledBy(() => doorScheduler.GetScheduleAsJson());

      var credentials = CredentialValidatorFactory.CreateSimpleValidator("Bootstrapper", "admin", "hnsefyk");
      var webService = new WebService(c_servicePort, credentials, config);

      string prefix = Name + ": ";
      webService.Logging.OnLogInfo += message => Logger.Instance.LogInfo(prefix + message);
      webService.Logging.OnLogError += message => Logger.Instance.LogError(prefix + message);
      webService.Logging.OnLogException += (message, ex) => Logger.Instance.LogException(prefix + message, ex);

      webService.Start();
    }
    public void Start()
    {
      Logger.Instance.LogInfo("MainController start");

      // All background tasks are maintained by the TaskRunner
      var tasks = new TaskRunner();

      // Make sure the RTC is correct
      tasks.RunForever("RTC", KeepClockAlive);

      // Create and start the machinery. Init will block until it is completely ready.
      var machinery = new Machinery();
      machinery.Start();
      tasks.RunForever("Machinery Sequencer", machinery.Sequencer.Start);

      // Blink 3 times to show we're starting up
      machinery.BlinkLED(300, 300, 300, 300, 300);

      // Setup manual control of the doors
      machinery.PushButton.ButtonPressed += (s, e) =>
      {
        Logger.Instance.LogInfo("PushButton press " + e.PressCount);
        if (machinery.Sequencer.IsBusy) // ignore button-initiated control if doors are already busy
        {
          Logger.Instance.LogInfo("Doors are busy, pushbutton ignored");
          return;
        }
        var door =
          e.PressCount == 1 ? machinery.DoorCoop :
          /*TODO remove for OfflineDoor e.PressCount == 2 ? machinery.DoorYard :*/ null;
        if (door != null)
        {
          machinery.Sequencer.Enqueue(() =>
            {
              if (door.Status == DoorStatus.Closed)
                door.OpenCompletely();
              else
                door.CloseCompletely();
            });
        }
      };

      // Setup the automatic door schedule
      var doorScheduler = new DoorScheduler();
      doorScheduler.Morning += () => machinery.Sequencer.Enqueue(() =>
      {
        machinery.DoorCoop.OpenCompletely();
      });
      doorScheduler.Evening += () => machinery.Sequencer.Enqueue(() =>
      {
        machinery.DoorYard.CloseCompletely();
        machinery.DoorCoop.CloseCompletely();
        machinery.Power1.On = false;
        machinery.Power2.On = false;
      });
      tasks.RunForever("Door Schedule", doorScheduler.Start);

      // TODO: lamp schedule?

      // TODO: safety thread?

      // Start the web server
      var webcontrol = new WebControl();
      tasks.RunForever(webcontrol.Name, () => webcontrol.Start(machinery, doorScheduler));

      // Blink 3 times fast slowly after a brief pause to show that setup has completed
      Thread.Sleep(1000);
      machinery.BlinkLED(100, 300, 100, 300, 100);
    }