physical/physical-traffic-light.js

const {Light, TrafficLight} = require('../traffic-light/traffic-light');

///////////////

const RED=0, YELLOW=1, GREEN=2;
const ON=1, OFF=0;

///////////////

/**
 * A physical light in a traffic light.
 * @memberof physical
 * @extends trafficLight.Light
 */
class PhysicalLight extends Light {

  /**
   * @param {number} lightNum - The light number for this light.
   * @param {physical.Device} device - The device associated with this light.
   */
  constructor(lightNum, device) {
    super();
    this.lightNum = lightNum;
    this.device = device;
  }

  /**
   * Toggles the light if its device is connected.
   * @see physical.Device#turn
   */
  async toggle() {
    if (!this.device.isConnected) return;
    super.toggle();
    await this.device.turn(this.lightNum, +this.on);
  }

  /**
   * Turn the light on if its device is connected.
   * @see physical.Device#turn
   */
  async turnOn() {
    if (!this.device.isConnected) return;
    super.turnOn();
    await this.device.turn(this.lightNum, ON);
  }

  /**
   * Turn the light off if its device is connected.
   * @see physical.Device#turn
   */
  async turnOff() {
    if (!this.device.isConnected) return;
    super.turnOff();
    await this.device.turn(this.lightNum, OFF);
  }

  /**
   * Syncs the physical light in the device with the state of this instance.
   * @see physical.Device#turn
   */
  async sync() {
    if (!this.device.isConnected) return;
    await this.device.turn(this.lightNum, +this.on);
  }

}

///////////////

/**
 * A physical traffic light.
 * @memberof physical
 * @extends trafficLight.TrafficLight
 */
class PhysicalTrafficLight extends TrafficLight {

  /**
   * @param {physical.Device} device - The device associated with this traffic light.
   * @param {physical.PhysicalLight} [red] - Red light.
   * @param {physical.PhysicalLight} [yellow] - Yellow light.
   * @param {physical.PhysicalLight} [green] - Green light.
   */
  constructor(device, red, yellow, green) {
    super(
      red || new PhysicalLight(RED, device),
      yellow || new PhysicalLight(YELLOW, device),
      green || new PhysicalLight(GREEN, device));
    this.device = device;
    this.device.on('connected', () => this.emit('enabled'));
    this.device.on('disconnected', () => this.emit('disabled'));
  }

  async reset() {
    if (!this.isConnected) return;
    await Promise.all([
      this.red.turnOff(),
      this.yellow.turnOff(),
      this.green.turnOff()
    ]);
  }

  /**
   * Syncs the physical lights in the device with the state of this instance.
   */
  async sync() {
    if (!this.isConnected) return;
    await Promise.all([
      this.red.sync(),
      this.yellow.sync(),
      this.green.sync()
    ]);
  }

  /**
   * If the traffic light is enabled and ready to use.
   * Same as `isConnected`.
   * @type {boolean}
   */
  get isEnabled() {
    return this.isConnected;
  }

  /**
   * If the traffic light's device is connected.
   * Same as `isEnabled`.
   * @type {boolean}
   */
  get isConnected() {
    return this.device.isConnected;
  }

  toString() {
    return `device ${this.device.serialNum}`;
  }

}

///////////////

module.exports = {
  RED, YELLOW, GREEN,
  ON, OFF,
  PhysicalLight, PhysicalTrafficLight
};