Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Uplink Decoder:

Code Block
languagejs
// Decode uplink function.
//
// Input is an object with the following fields:
// - bytes = Byte array containing the uplink payload, e.g. [255, 230, 255, 0]
// - fPort = Uplink fPort.
// - variables = Object containing the configured device variables.
//
// Output must be an object with the following fields:
// - output = Object representing the decoded payload.
function decodeUplink(input) {
  return {
    data: Decode(input.fPort, input.bytes, input.variables)
  };
}

function get_user_mode(input) {
  var user_mode = input[9] & 0x7;
  switch (user_mode) {
    case 0:
      return "Valve_Position";
    case 1:
      return "RESERVED";
    case 2:
      return "SP_Ambient_Temperature";
    case 3:
      return "Detecting_Opening_Point";
    case 4:
      return "Slow_Harvesting";
    case 5:
      return "Temperature_Drop";
    case 6:
      return "Freeze_Protect";
    case 7:
      return "Forced_Heating";
    default:
      return "Unknown Operating Mode";
  }
}

function get_user_value(input) {
  var user_mode = get_user_mode(input);
  switch (user_mode) {
    case "Valve_Position":
    case "Freeze_Protect":
    case "Forced_Heating":
      return input[10];
    case "SP_Ambient_Temperature":
      return input[10] * 0.5;
    case "Detecting_Opening_Point":
    case "Slow_Harvesting":
      return input[10] * 0.25;
    default:
      return "Invalid User Mode";
  }
}

function decode_port_1(input) {
  var output = {
    Current_Valve_Position: input[0],
    Flow_Sensor_Raw: input[1] * 0.5,
    Flow_Temperature: input[2] * 0.5,
    Ambient_Sensor_Raw: input[3] * 0.25,
    Ambient_Temperature: input[4] * 0.25,
    Temperature_Drop_Detection: input[5] >> 7 & 0x01,
    Energy_Storage: input[5] >> 6 & 0x01,
    Harvesting_Active: input[5] >> 5 & 0x01,
    Ambient_Sensor_Failure: input[5] >> 4 & 0x01,
    Flow_Sensor_Failure: input[5] >> 3 & 0x01,
    Radio_Communication_Error: input[5] >> 2 & 0x01,
    Received_Signal_Strength: input[5] >> 1 & 0x01,
    Motor_Error: input[5] >> 0 & 0x01,
    Storage_Voltage: Number((input[6] * 0.02).toFixed(2)),
    Average_Current_Consumed: input[7] * 10,
    Average_Current_Generated: input[8] * 10,
    Operating_Condition: input[9] >> 7 & 0x01,
    Storage_Fully_Charged: input[9] >> 6 & 0x01,
    Zero_Error: input[9] >> 5 & 0x01,
    Calibration_OK: input[9] >> 4 & 0x01,
  }
   var um = input[9] & 0x07;
  var uv = (um === 0) ? input[10] : input[10] * 0.5;
  output.User_Mode = umget_user_mode(input);
  output.User_Value = uvget_user_value(input);

  if (input.length == 12) {
    utmp = input[11] * 0.25;
    output.Used_Temperature = utmp;
  }
  return output;
}


function Decode(fPort, bytes) {
  var output = {};
  switch (fPort) {
    case 1:
      output = decode_port_1(bytes);
      break;
    default:
      return {
        errors: ['unknown FPort'],
      };
  }
  return output;
}

Downlink Encoder:

Code Block
languagejs
// Encode downlink function.
//
// Input is an object with the following fields:
// - output = Object representing the payload that must be encoded.
// - variables = Object containing the configured device variables.
//
// Output must be an object with the following fields:
// - bytes = Byte array containing the downlink payload.

// Possible Options:
// userMode          : "Ambient_Temperature" or "Valve_Position"
// setValue          : 0 to 40  (0.5° resolution) for "Ambient_Temperature"
// setValue          : 0 to 100 (1% resolution)   for "Valve_Position"

// safetyMode        : "Ambient_Temperature" or "Valve_Position"
// safetyValue       : 0 to 40  (0.5° resolution) for "Ambient_Temperature"
// safetyValue       : 0 to 100 (1% resolution)   for "Valve_Position"

// roomTemperature   : 0 (Internal Ambient Estimate) or Temperature from External Sensor (0.25° resolution)
// radioInterval     : 5 or 10 or 60 or 120 or 480 (minutes)
// doReferenceRunNow : 0 or 1 (0-False; 1-True)

function encodeDownlink(input) {
  let mode = input.data.userMode; // "Ambient_Temperature" or "Valve_Position"
  let safetyMode = input.data.safetyMode; // "Ambient_Temperature" or "Valve_Position"
  let setValue = input.data.setValue; // 0-40 for Ambient_Temperature, 0-100 for Valve_Position
  let roomTemperature = input.data.roomTemperature; // 0-40
  let safetyValue = input.data.safetyValue; // 0-40 for Ambient_Temperature, 0-100 for Valve_Position
  let radioInterval = input.data.radioInterval; // 5, 10, 60, 120, 480
  let doReferenceRunNow = input.data.doReferenceRunNow; // 0 or 1

  let bytes = [0, 0, 0, 0, 0, 0];

  // Byte 1: Set value
  if (mode === "Ambient_Temperature") {
      if (setValue < 0 || setValue > 40) {
        throw new Error("Set value out of range for ambient mode");
      }
      else {
        bytes[0] = setValue *2;
      }         
  } else if (mode === "Valve_Position") {
      if (setValue < 0 || setValue > 100) {
        throw new Error("Set value out of range for valve mode");
      } 
      else {
        bytes[0] = setValue;
      }
  } else {
      throw new Error("Invalid user mode");
  }

  // Byte 2: Room temperature (0-40)
  if (roomTemperature < 0 || roomTemperature > 40) {
    throw new Error("Room temperature out of range");
  }
  else {
  bytes[1] = roomTemperature * 4;
  }

  // Byte 3: Safety value
  if (safetyMode === "Ambient_Temperature") {
      if (safetyValue < 0 || safetyValue > 40) {
        throw new Error("Safety value out of range for ambient mode");
      } 
      else {
        bytes[2] = safetyValue * 2;
      }
  } else if (safetyMode === "Valve_Position") {
      if (safetyValue < 0 || safetyValue > 100) {
        throw new Error("Safety value out of range for valve mode");
      } 
      else {
        bytes[2] = safetyValue;
      }
  } else {
      throw new Error("Invalid safety mode");
  }

  // Byte 4: Radio interval, user mode, safety mode
  let radioBits;
  switch (radioInterval) {
      case 5:
          radioBits = 1 << 4; // Radio interval 5 minutes
          break;
      case 10:
          radioBits = 0 << 4; // Radio interval 10 minutes
          break;
      case 60:
          radioBits = 2 << 4; // Radio interval 60 minutes
          break;
      case 120:
          radioBits = 3 << 4; // Radio interval 120 minutes
          break;
      case 480:
          radioBits = 4 << 4; // Radio interval 480 minutes
          break;
      default:
          throw new Error("Invalid radio interval");
  }

  let userModeBits;
  if (mode === "Ambient_Temperature") {
      userModeBits = 2 << 2; // User mode "Ambient_Temperature" in bits 3 and 4
  } else {
      userModeBits = 0 << 2; // User mode "Valve_Position" in bits 3 and 4
  }

  let safetyModeBits;
  if (safetyMode === "Ambient_Temperature") {
      safetyModeBits = 0 << 0; // Safety mode "Ambient_Temperature" in bits 1 and 2
  } else {
      safetyModeBits = 2 << 0; // Safety mode "Valve_Position" in bits 1 and 2
  }

  bytes[3] = radioBits | userModeBits | safetyModeBits;

  // Byte 5: Reserved (set to 0)
  bytes[4] = 0;

  // Byte 6: doReferenceRunNow bit (bit 8)
  if (doReferenceRunNow < 0 || doReferenceRunNow > 1) {
    throw new Error("Invalid doReferenceRunNow value");
  }
  else {
    bytes[5] = doReferenceRunNow << 7;
  }

  return {
      "bytes": bytes
  };
}

Downlink Encoder Example:

Code Block
languagejsjson
// Example 1
{
      "userMode": "Valve_Position",
      "setValue": 42,
      "roomTemperature": 0,
      "safetyMode": "Ambient_Temperature",
      "safetyValue": 19,
      "radioInterval": 5, 
      "doReferenceRunNow": 1
}

// Example 2
{
      "userMode": "Ambient_Temperature",
      "setValue": 21.5,
      "roomTemperature": 24,
      "safetyMode": "Valve_Position",
      "safetyValue": 0,
      "radioInterval": 60, 
      "doReferenceRunNow": 0
}

// Example 3
{
      "userMode": "Valve_Position",
      "setValue": 36,
      "roomTemperature": 0,
      "safetyMode": "Valve_Position",
      "safetyValue": 21,
      "radioInterval": 5, 
      "doReferenceRunNow": 1 
}

// Example 4
{
      "userMode": "Ambient_Temperature",
      "setValue": 20.5,
      "roomTemperature": 23.75,
      "safetyMode": "Ambient_Temperature",
      "safetyValue": 18,
      "radioInterval": 10, 
      "doReferenceRunNow": 0 
}