import stamp.core.*;
import stamp.util.text.*; // http://www.parallax.com/javelin/applications.asp#AN012
import stamp.peripheral.x10.insteon.*; // http://www.cls01.com/insteon

/*******************************************************************************
* Demo program for Javelin INSTEON Class:
*   Automatic Control of Bathroom Fan and Stairway Lights
*   (http://www.cls01.com/insteon/demo1)
*
* @author Scott Herr (http://www.cls01.com/insteon)
* @version 1.01 April 23, 2006
*******************************************************************************/

//------------------------------------------------------------------------------
// This demo program has two main functions:
//   1. Automatically turn on the bathroom fan 2 minutes for every
//      1 minute the bathroom light is on. Fan turns on 5 seconds
//      after the bathroom lights are turned off.
//   2. Dim the stairway lights 10 seconds after they're turned on
//      and turn on entryway lights at the same time.
//
// See http://www.cls01.com/insteon/demo1 for details about INSTEON
// devices that are used in this program.
//------------------------------------------------------------------------------

public class InsteonDemo1 {

  // INSTEON PowerLinc V2 Settings
  static final int PLCpinTX = CPU.pin9;
  static final int PLCpinRX = CPU.pin10;
  static Uart PLCtx = new Uart(Uart.dirTransmit, PLCpinTX, Uart.dontInvert, Uart.speed4800, Uart.stop1);
  static Uart PLCrx = new Uart(Uart.dirReceive, PLCpinRX, Uart.dontInvert, Uart.speed4800, Uart.stop1);
  static Timer PLCtimer = new Timer();
  static Insteon PLC = new Insteon(PLCtx,PLCrx,PLCtimer);

  // CONSTANTS
  final static String version = "InsteonDemo1 V1.01";
  final static char[] bathroomLightSwitch = {0x04,0x42,0x00}; // INSTEON address
  final static char[] bathroomFanSwitch   = {0x04,0x35,0xf8}; // INSTEON address
  final static char[] stairsLightSwitch   = {0x03,0xb5,0x04}; // INSTEON address
  final static char[] entryLightSwitch    = {0x06,0x1e,0xf1}; // INSTEON address

  // VARIABLES
  static boolean bathroomLightOn = false;
  static int bathroomLightOnMinutes = 0;
  static boolean autoStartBathroomFan = false;
  static boolean bathroomFanTimerOn = false;
  static boolean stairwayLightTurnedOn = false;
  static ScaledTimer16 tBathroomLight = new ScaledTimer16(0,10000); // timeUnit=0.1sec
  static ScaledTimer16 tBathroomFanDelay = new ScaledTimer16(0,10000); // timeUnit=0.1sec
  static ScaledTimer16 tBathroomFanOnTime = new ScaledTimer16(0,10000); // timeUnit=0.1sec
  static ScaledTimer16 tStairwayDimDelay = new ScaledTimer16(0,10000); // timeUnit=0.1sec
  static char[] eventBuffer = new char[32];
  static int rtnCode;

  //****************************************************************************
  // Main Program
  //****************************************************************************
  static void main() {
    int i;
    Format.printf("PROGRAM: %s\n",version);
    Format.printf("- Javelin free memory = %d\n",Memory.freeMemory());
    // Monitor for events
    Format.printf("Monitoring for events...\n");
    while (true) {
      // Poll for events
      rtnCode = PLC.poll();
      if (rtnCode < 0) Format.printf("Poll error %d\n",rtnCode);
      // Read events from buffer
      while (PLC.readNextEvent(eventBuffer) == 0) {
        processEvent();
        //DEBUG Format.printf("- Javelin free memory = %d\n",Memory.freeMemory());
      }
      // Check if bathroom light is on - if so, count minutes
      if (bathroomLightOn && tBathroomLight.timeout()) {
        tBathroomLight.mark();
        bathroomLightOnMinutes++;
      }
      // Check if time to turn bathroom fan on
      if (autoStartBathroomFan && tBathroomFanDelay.timeout()) {
        autoStartBathroomFan = false;
        i = bathroomLightOnMinutes * 2;     // Run fan 2:1 light on minute
        if (i > 15) i = 15;                 // Maximum 15 minutes
        tBathroomFanOnTime.mark(i * 600 + 10);
        bathroomFanTimerOn = true;
        if (i > 0) {                        // Turn bathroom fan on
          rtnCode = PLC.sendInsteonCmd(Insteon.CMDTYPE_DIRECT,
            bathroomFanSwitch,Insteon.CMD_ON,Insteon.CMD2_FULL_ON);
          if (rtnCode < 0) Format.printf("Send error %d\n",rtnCode);
          else             Format.printf("Bathroom fan turned on %d minutes...\n",i);
        }
      }
      // Check if time to turn bathroom fan off
      if (bathroomFanTimerOn && tBathroomFanOnTime.timeout()) {
        bathroomFanTimerOn = false;
        rtnCode = PLC.sendInsteonCmd(Insteon.CMDTYPE_DIRECT,
          bathroomFanSwitch,Insteon.CMD_OFF,(char)0);
        if (rtnCode < 0) Format.printf("Send error %d\n",rtnCode);
        else             Format.printf("Bathroom fan turned off...\n");
      }
      // Check if time to dim stairway light
      if (stairwayLightTurnedOn && tStairwayDimDelay.timeout()) {
        stairwayLightTurnedOn = false;
        rtnCode = PLC.sendInsteonCmd(Insteon.CMDTYPE_DIRECT,
          stairsLightSwitch,Insteon.CMD_ON,(char)0x28);
        if (rtnCode < 0) Format.printf("Send error %d\n",rtnCode);
        else             Format.printf("Stairway reset to level 0x28...\n");
        rtnCode = PLC.sendInsteonCmd(Insteon.CMDTYPE_DIRECT,
          entryLightSwitch,Insteon.CMD_ON,(char)0x38);
        if (rtnCode < 0) Format.printf("Send error %d\n",rtnCode);
        else             Format.printf("Entry lights set to level 0x38...\n");
      }
    }
  } // END main

  //****************************************************************************
  // Subroutines
  //****************************************************************************

  /**
   * processEvent: Take action for interesting events
   */
  static void processEvent() {
    int i;
    // Display event details
    Format.printf("Event: ");
    for (i=1;i<=eventBuffer[0];i++) {
      Format.printf("[%02x]",(eventBuffer[i] & 0xff));
    }
    Format.printf("\n");
    // Check if bathroom light switched on
    if ((PLC.eventType == Insteon.IBIOS_INSTEON_MSG_RECD)
      && (PLC.eventHandle == Insteon.EVNT_IRX_MYMSG)
      && (PLC.addrEquals(PLC.eventFromAddress,bathroomLightSwitch))
      && (PLC.eventCmd1 == Insteon.CMD_ON)) {
      bathroomLightOn = true;
      bathroomLightOnMinutes = 0;
      autoStartBathroomFan = false;         // Cancel any autostart in progress
      bathroomFanTimerOn = false;           // Resume manual control of fan
      tBathroomLight.mark(600);             // Count # of minutes light on
      Format.printf("Bathroom light on...\n");
    }
    // Check if bathroom light switched off
    if ((PLC.eventType == Insteon.IBIOS_INSTEON_MSG_RECD)
      && (PLC.eventHandle == Insteon.EVNT_IRX_MYMSG)
      && (PLC.addrEquals(PLC.eventFromAddress,bathroomLightSwitch))
      && (PLC.eventCmd1 == Insteon.CMD_OFF)) {
      if (bathroomLightOn) {
        bathroomLightOn = false;
        autoStartBathroomFan = true;
        tBathroomFanDelay.mark(50);         // Wait 5 seconds before autostarting bathroom fan
      }
      Format.printf("Bathroom light off...\n");
    }
    // Check if stairway light switched on
    if ((PLC.eventType == Insteon.IBIOS_INSTEON_MSG_RECD)
      && (PLC.eventHandle == Insteon.EVNT_IRX_MYMSG)
      && (PLC.addrEquals(PLC.eventFromAddress,stairsLightSwitch))
      && (PLC.eventCmd1 == Insteon.CMD_ON)) {
      stairwayLightTurnedOn = true;
      tStairwayDimDelay.mark(100);          // Wait 10 seconds before dimming lights
      Format.printf("Stairs on...\n");
    }
  } // END processEvent

} // END class