assert = require 'assert'

controller = require '../src/controller.coffee'
controller.debug = yes

describe '#decodePulses()', ->
  tests = [
    {
      protocol: 'generic'
      pulseLengths: [671, 2051, 4346, 10220]
      pulses: [
        '020102010201020101020102010201020102020101020201020102010102020101020201010202010201020102010201020102010201020102010201020102010201020102010201020102010201020102010201020102010201020102010201010203'
        '020102010201020101020102010201020102020101020201020102010102020101020201010202010201020102010201020102010201020102010201020102010201020102010201020102010102020102010102010201020201010202010201010203'
        '020102010201020101020102010201020102010202010201010201020102020101020201010202010201020102010201020102010201020102010201020102010102020102010201020102010102010202010201020101020102010202010201010203'
        '020102010201020101020102010201020102020101020201020102010102020101020201020102010201020102010201020102010201020102010201020102010102020102010201020102010102010202010201020101020102010202010201010203'
        '020102010201020101020102010201020102020101020201020102010102020101020201010201020102010201020102010201020102010201020102010201020102010201020102010201020102010201020102010201020102010201020102010203'
      ]
      values: [
        { id: 1000, type: 10, positive: true, value: 1 }
        { id: 1000, type: 10, positive: true, value: 1257 }
        { id: 1011, type: 10, positive: true, value: 67129 }
        { id: 1000, type: 10, positive: false, value: 67129 }
        { id: 1000, type: 10, positive: true, value: 1073741823 }
      ]
    },
    {
      protocol: 'generic2'
      pulseLengths: [480, 1320, 13320]
      pulses: [
          '011010101010101001011010101010101010101010010101101001101010100102'
          '010110101010101001011010101010101010101010010101101001101010100102'
      ]
      values: [
        { id: 123, type: 1, value: 1023, freq: 3, battery: 99, checksum: true}
        { id: 123, type: 1, value: 1023, freq: 3, battery: 99, checksum: false}
      ]
    },
    {
      protocol: 'alarm3'
      pulseLengths: [472, 1236, 11688]
      pulses: [
        '100101010101100101011010010101101010101001011010000102'
        '011001100110011001100110011001100110011001100110000002'
        '011010101001010110010110100110101010101010100101111112'
        '011010101001001110010110100110101010101010100101111112'
        '101010100110100110100110010110100110101001011010000002'
      ]
      values: [
        { id: 9787738, state: true }
        { id: 6710886, state: true }
        { id: 6985110, state: true }
        { id: 6986089, state: true }
        { id: 11168166, state: true }
      ]
    },
    {
      protocol: 'pir1'
      pulseLengths: [358, 1095, 11244]
      pulses: [
        '01100101011001100110011001100110011001010110011002'
        '01100110011001100110010101100110011001010110011002'
        '01100110011001010110011001100110010101100110011002'
      ]
      values: [
        { unit: 8, id: 1, presence: true }
        { unit: 0, id: 17, presence: true }
        { unit: 2, id: 2, presence: true }
      ]
    },
    {
      protocol: 'pir2'
      pulseLengths: [451, 1402, 14356]
      pulses: [
        '01100110010110011001010110100101010101011010010102'
      ]
      values: [
        { unit: 21, id: 21, presence: true }
      ]
    },
    {
      protocol: 'pir4'
      pulseLengths: [ 371, 1081, 5803 ]
      pulses: [
        '110100110101001101010011001010101012'
      ]
      values: [
        { id: 54099, unit: 21290, presence: true }
      ]
    },
    {
      protocol: 'pir6'
      pulseLengths: [ 288, 864, 8964 ]
      pulses: [
        '01011010010101011010100110010101101001010101101002'
        '01011010010101011010100110010101101001010110010102'
        '01011010010101011010100110010101101001011001010102'
      ]
      values: [
        { id: 6410630, presence: true }
        { id: 6410632, presence: true }
        { id: 6410640, presence: true }
      ]
    },
    {
      protocol: 'weather1'
      pulseLengths: [456, 1990, 3940, 9236]
      pulses: [
        '01020102020201020101010101010102010101010202020102010101010102010101020103'
        '01020102010201010101020202020101010101020101010101020101010102020202010203'
        '01020102020201010102020102020101010101020101010101010101010102020202010103'
        '01020102010102020102020102020201010101010202020201020101010201010101020203'
      ]
      values: [
        { id: 208 ,channel: 2 ,lowBattery: true ,temperature: 23.2, humidity: 34 }
        { id: 67  ,channel: 1 ,lowBattery: false ,temperature: 26.0, humidity: 61 }
        { id: 198 ,channel: 1 ,lowBattery: false ,temperature: 25.6, humidity: 60 }
        { id: 54 ,channel: 3 ,lowBattery: false ,temperature: 24.4, humidity: 67 }
      ]
    },
    {
      protocol: 'weather2'
      pulseLengths: [492, 969, 1948, 4004]
      pulses: [
        '01010102020202010201010101010101020202010201020102020202010101010101010103'
        '01010102020202010201010101010101020202010201010202020202010101010101010103'
        '01010102020202010201010101010101020202010201010102020202010101010101010103'
        '01010101020201020201010101010102010101010202010102020202010101010101010103'
        '01010101020201020201010101010102010101010201010102020202010101010101010103'
        '02010102010102020201010102020202020102020102020102020202010101010202020103'
      ],
      values: [
        { temperature: 23.4 }
        { temperature: 23.3 }
        { temperature: 23.2 }
        { temperature: 26.8 }
        { temperature: 26.4 }
        { temperature: -7.4 }
      ]
    },
    {
      protocol: 'weather3'
      pulseLengths: [508, 2012, 3908, 7726]
      pulses: [
        '01010202020201020201010102010102020201020202010202010201010101010202010201010101020103'
        '01010202020201020201010102010201020201020202010202010201010101010202010201010202010103'
        '01010201020102020102010101010101010101020101010202010101010201020101010101010102010203'
        '01010201020102020102010101010102020201020101010202010101010201020101010101010102010103'
        '01010101010202020201010101020201010201010101010202010202020101010202010201010101010203'
        '01010101010202020201010101020102010201010102010202010202020201010202010101010202010103'
      ]
      values: [
        { id: 246, channel: 3, temperature: 24.2, humidity: 56 }
        { id: 246, channel: 3, temperature: 24.4, humidity: 56 }
        { id: 173, channel: 1, temperature: 21.1, humidity: 65 }
        { id: 173, channel: 1, temperature: 21.5, humidity: 65 }
        { id: 30,  channel: 2, temperature: 18.1, humidity: 62 }
        { id: 30,  channel: 2, temperature: 18.7, humidity: 63 }
      ]
    },
    {
      protocol: 'weather4'
      pulseLengths: [ 526, 990, 1903, 4130, 7828, 16076 ]
      pulses: [
        '11111111040303030203030302020302030203020302030302020202030302020202030303020202030202020305'
      ]
      values: [
        { id: 238, channel:1, temperature: 18.9, humidity: 71, lowBattery: false }
      ]
    },
    {
      protocol: 'weather5'
      pulseLengths: [ 534, 2000, 4000, 9120  ]
      pulses: [
        '01020101010201020102010101020202020202010101010102020201010202010202020203'
        '01010101010101010102020102020101020202010201010101010101010101010101010203'
        '01020202010101020102020102020101020102020202010101010101010101010102020103'
        '01020202010202020101010102010201020202010101010102010102020101020201020103'
        '01020202010202020101020101020101020202020202020202010102010202010101010103'
      ]
      values: [
        { id: 162, temperature: 12.6, humidity: 67, lowBattery: false }
        { id: 0, rain: 5.75, lowBattery: false }
        { id: 142, rain: 15.25, lowBattery: false }
        { id: 238, temperature: 11.7, humidity: 99,  lowBattery: false }
        { id: 238, temperature: -1.4, humidity: 69,  lowBattery: false }
      ]
    },
    {
      protocol: 'weather7'
      pulseLengths: [ 444, 1992, 3955, 9330 ]
      pulses: [
        '010202010201010202010101010101010101010202020102020202010202010103'
      ]
      values: [
        { id: 105, temperature: 2.9, humidity: 59, channel: 0, lowBattery: false }
      ]
    },
    {
      protocol: 'weather11'
      pulseLengths: [544, 1056, 1984, 3880]
      pulses: [
        '020202010202010102010101010101020101010202010201020202020101020201020201010101010103'
      ]
      values: [
        { id: 236, channel: 1, temperature: 28.2, humidity: 54, lowBattery: false }
      ]
    },
    {
      protocol: 'weather12'
      pulseLengths: [516, 2048, 4076, 8976]
      pulses: [
        '0102020201010102020101010101010101020202020102020201020102010202020102020103'
        '0201010202010202010101010101010101020201010202010202010202020102020201010203'
        '0201010202010202010101010101010101020202010202020201020101010102010202010103'
      ]
      values: [
        { id: 113, channel: 1, temperature: 12.3, humidity: 85, lowBattery: true }
        { id: 155, channel: 1, temperature: 10.2, humidity: 110, lowBattery: false }
        { id: 155, channel: 1, temperature: 11.9, humidity: 80, lowBattery: false }
      ]
    },
    {
      protocol: 'weather13'
      pulseLengths: [492, 992, 2028, 4012]
      pulses: [
        '02020202010101020201020101010101020202010202010202020202010102020101010103'
      ]
      values: [
        { id: 241, channel: 3, temperature: 23.7, humidity: 48, lowBattery: false }
      ]
    },
    {
      protocol: 'weather14'
      pulseLengths: [480, 1960, 3908, 8784]
      pulses: [
        '0102020102010202010101020202020202020202010101010102010201010202010102020203'
        '0102020102010202010101020202020201010101010102010102020101010202010102020203'
        '0201010201020102010101010102020101010102010101010202020202020101020201010103'
        '0201010201020102010101010102010201010102010101010202010102020101020201010103'
      ]
      values: [
        { id: 78, channel: 1, temperature: 25, lowBattery: true }
        { id: 78, channel: 1, temperature: -3.9, lowBattery: true }
        { id: 175, channel: 3, temperature: -27.2, humidity: 51, lowBattery: false }
        { id: 175, channel: 3, temperature: -26.9, humidity: 51, lowBattery: true }
      ]
    },
    {
      protocol: 'weather15'
      pulseLengths: [480, 1960, 3908, 8784]
      pulses: [
        '0201010202010102010101010102010101010101020202010101020101020101010102010203'
        '0201010202010102010101010102010201010101020202010101020101020101010102010203'
        '0201010202010102010101010102020101010101020202010101020101020101010102010203'
        '0201010201010202010102020201010102020202020201020201020201010101020102010203'
      ]
      values: [
        { id: 2448, channel: 1, temperature: 22.6, humidity: 66, lowBattery: false }
        { id: 2448, channel: 2, temperature: 22.6, humidity: 66, lowBattery: false }
        { id: 2448, channel: 3, temperature: 22.6, humidity: 66, lowBattery: false }
        { id: 2355, channel: 1, temperature: -3.7, humidity: 10, lowBattery: true }
      ]
    },
    {
      protocol: 'weather16'
      pulseLengths: [472, 1964, 4052, 8904]
      pulses: [
        '02020202010202010101020101010201010101010201010101010101010102020102010203'
        '02020202010202010101020101010101010101010201010102010101010102020202020103'
      ]
      values: [
        { id: 111, channel: 1, temperature: 26, humidity: 36, lowBattery: false }
        { id: 111, channel: 1, temperature: 25.6, humidity: 37, lowBattery: false }
      ]
    },
    {
      protocol: 'weather17'
      pulseLengths: [444, 1160, 28580]
      pulses: [
        '1111111101110111111111111111010111111111110101011111111111111101110101011111111101011112'
        '1111111101110111111111111111010111111101110101011111011101111111110101011111011101111112'
        '1111111101110111010101111111010111111101110101111111011111111111110101111111011101011112'
        '1111111101110111010101111111010111111101110101111111110111111111110101111111110101110112'
      ]
      values: [
        { id: 24, channel: 0, temperature: 20.1 }
        { id: 24, channel: 0, temperature: 22.8 }
        { id: 24, channel: 7, humidity: 62 }
        { id: 24, channel: 7, humidity: 61 }
      ]
    },
    {
      protocol: 'weather18'
      pulseLengths: [496, 960, 1940, 3904]
      pulses: [
        '0101020102020102020101010101010102020201010102020202020201020202010202020003'
        '0101020102020102020101010101010102020202010102020202020201010102020101020003'
        '0101020102020102020101010101010201010201010101010202020202010202010202010003'
        '0101020102020102020101010101010201010102010101010202020201010101010201010003'
      ]
      values: [
        { id: 45, channel: 1, temperature: 22.7 }
        { id: 45, channel: 1, temperature: 24.3 }
        { id: 45, channel: 1, temperature: 28.8 }
        { id: 45, channel: 1, temperature: 27.2 }
      ]
    },
    {
      protocol: 'weather19'
      pulseLengths: [548, 1008, 1996, 3936]
      pulses: [
        '020202010101010101010101010101020101010102010201020101010201020203'
        '020102020102010101010101010101020101020101020201010102020201020203'
        '020102020102010101010101010101020101020201010101020102010102010203'
        '020102020102010101010101010101020202010102020101020102010101010203'
      ]
      values: [
        { id: 56, channel: 1, temperature: 26.6 }
        { id: 45, channel: 1, temperature: 29.4 }
        { id: 45, channel: 1, temperature: 30.4 }
        { id: 45, channel: 1, temperature: 46.0 }
      ]
    },
    {
      protocol: 'weather20'
      pulseLengths: [560, 972, 1904, 3812, 8556]
      pulses: [
        '0302020302020202030202020302020202020202030302020202030202020202020202020104'
        '0302020302020202030202020302020202020202030203030302030202020202020202020104'
        '0302020302020202030202020302020202020202030203030302030302020202020202020104'
        '0302020302020202030302030302020302020202030302020203030202020202020202020104'
        '0302020302020202030303020302020202020202030302020203020302020202020202020104'
        '0302020302020202030303020302020202020202030302020202020302020202020202020104'
        '0302020302020202030303020302020202020202030302020302020202020202020202020104'
      ]
      values: [
        { id: 2312, channel: 1, temperature: 19.4, lowBattery: true }
        { id: 2312, channel: 1, temperature: 18.6, lowBattery: true }
        { id: 2312, channel: 1, temperature: 18.7, lowBattery: true }
        { id: 2317, channel: 2, temperature: 19.8, lowBattery: true }
        { id: 2318, channel: 1, temperature: 19.7, lowBattery: true }
        { id: 2318, channel: 1, temperature: 19.3, lowBattery: true }
        { id: 2318, channel: 1, temperature: 20, lowBattery: true }
      ]
    },
    {
      protocol: 'dimmer1'
      pulseLengths: [259, 1293, 2641, 10138]
      pulses: [
        '0200010001010000010001010000010001000101000100010001000100000101000100010000010001000100010001010001000001000101000001000100010001010001000100010003'
      ],
      values: [
        {id: 9565958, all: false, unit: 0, dimlevel: 15, state: true}
      ]
    },
    {
      protocol: 'switch1'
      pulseLengths: [268, 1282, 2632, 10168]
      pulses: [
        '020001000101000001000100010100010001000100000101000001000101000001000100010100000100010100010000010100000100010100000100010001000103'
        '020001000101000001000100010100010001000100000101000001000101000001000100010100000100010100010000010100000100010100000100010001010003'
        '020001000101000001000100010100010001000100000101000001000101000001000100010100000100010100010000010100000100010001000100010001010003'
      ],
      values: [
        { id: 9390234, all: false, state: true, unit: 0 }
        { id: 9390234, all: false, state: true, unit: 1 }
        { id: 9390234, all: false, state: false, unit: 1 }
      ]
    },
    {
      protocol: 'switch2'
      pulseLengths: [306, 957, 9808]
      pulses: [
        '01010101011001100101010101100110011001100101011002'
      ],
      values: [
        { houseCode: 25, unitCode: 16, state: true }
      ]
    },
    {
      protocol: 'switch4'
      pulseLengths: [ 295, 1180, 11210 ],
      pulses: [
        '01010110010101100110011001100110010101100110011002'
      ],
      values: [
         { id: 2, unit: 20, state: true }
      ]
    },
    {
      protocol: 'switch5'
      pulseLengths: [295, 886, 9626]
      pulses: [
        '10010101101010010110010110101001010101011010101002'
        '10010101101010010110010110101001010101011010100102'
        '10010101101010010110010110101001010101011010011002'
        '10010101101010010110010110101001010101011010010102'
        '10010101101010010110010110101001010101011001101002'
        '10010101101010010110010110101001010101011001100102'
        '10010101101010010110010110101001010101010110101002'
        '10010101101010010110010110101001010101010110100102'
        '10010101101010010110010110101001010101010101011002'
        '10010101101010010110010110101001010101010101100102'
     ],
      values: [
        { id: 465695, unit: 1, all: false, state: on }
        { id: 465695, unit: 1, all: false, state: off }
        { id: 465695, unit: 2, all: false, state: on }
        { id: 465695, unit: 2, all: false, state: off }
        { id: 465695, unit: 3, all: false, state: on }
        { id: 465695, unit: 3, all: false, state: off }
        { id: 465695, unit: 4, all: false, state: on }
        { id: 465695, unit: 4, all: false, state: off }
        { id: 465695, unit: 0, all: true, state: off }
        { id: 465695, unit: 0, all: true, state: on }
      ]
    },
    {
      protocol: 'switch6'
      pulseLengths: [ 150, 453, 4733],
      pulses: [
        '10101010101010101010010101100110011001100110010102'
        '10101010101010100110011001010110011001100110010102'
      ],
      values: [
         { systemcode: 31, programcode: 1, state: true }
         { systemcode: 15, programcode: 2, state: true }
      ]
    },
    {
      protocol: 'switch7'
      pulseLengths: [307, 944, 9712],
      pulses: [
        '01010101010101100110011001100110011001100110011002'
        '01010101010101100101010101010110011001100110011002'
        '10100101011001100101010101010110011001100110011002'
      ],
      values: [
         { id: 0, unit: 3, state: true }
         { id: 7, unit: 3, state: true }
         { id: 7, unit: 1, state: false }
      ]
    },
    {
      protocol: 'switch8'
      pulseLengths: [ 173, 563, 5740],
      pulses: [
        '01010101010101010110011001100110101001011010010102'
        '01010101010101010110011001101010010101010101101002'
      ],
      values: [
         { systemcode: 30, programcode: 'B1', state: false }
         { systemcode: 30, programcode: 'C3', state: true }
      ]
    },
    {
      protocol: 'switch9'
      pulseLengths: [ 305, 615, 23020],
      pulses: [
        '0110100101100110011010101001101010101001011012'
        '0110100101100110011010101001101010101001101012'
        '0110100101100110011010101001101010101010011012'
        '0110100101100110011010101001101010010101100112'
      ],
      values: [
         { id: 2472, unit: 65, state: true }
         { id: 2472, unit: 65, state: false }
         { id: 2472, unit: 64, state: true }
         { id: 2472, unit: 71, state: false }
      ]
    },
    {
      protocol: 'switch10'
      pulseLengths: [ 271, 1254, 10092 ],
      pulses: [
        '01010000000101010100000100010101010000000101010100000101000100000101000101010001000100010001010001000101000000010102'
      ],
      values: [
         { id:3162089194, unit:35, all:false, state:false }
      ]
    },
    {
      protocol: 'switch11'
      pulseLengths: [ 566, 1267, 6992 ],
      pulses: [
        '100101010110011010101001101001010101100110010110011010100110011002'
        '100101011010011010101001101001010101100110010110011010100110011002'
        '100101101001011010101001101001010101100110010110011010100110011002'
        '100101100110011010101001101001010101100110010110011010100110011002'
      ],
      values: [
         { id: 34037, unit: 1, state: true }
         { id: 34037, unit: 1, state: false }
         { id: 34037, unit: 0, state: true }
         { id: 34037, unit: 0, state: false }
      ]
    },
    {
      protocol: 'switch12'
      pulseLengths: [ 564, 1307, 3237, 51535 ],
      pulses: [
        '1202021212021212121212121212021212121212121212121203'
        '1202021212021212121212121212121212121202121202021203'
        '1202021212021212121212121212121212021212121202120213'
        '1202021212021212121212121212121202121212121202120203'
      ],
      values: [
         { id: 9983, unit: 1, state: true }
         { id: 9983, unit: 1, state: false }
         { id: 9983, unit: 2, state: true }
         { id: 9983, unit: 3, state: true }
      ]
    },
    {
      protocol: 'switch13'
      pulseLengths: [ 700, 1400, 81000 ]
      pulses: [
        '001100110101001010101010101010110010101102'
        '001100110101001010101010101010101010101012'
        '001100110101001010101010101010101100110012'
        '001100110101001010101010101010110100110102'
      ],
      values: [
         { id:1472, unit:0, all:false, state:true,  dimm:false}
         { id:1472, unit:0, all:false, state:false, dimm:false}
         { id:1472, unit:0, all:false, state:false, dimm:true }
         { id:1472, unit:0, all:false, state:true,  dimm:true }
      ]
    },
    {
      protocol: 'switch14'
      pulseLengths: [ 208, 624, 6556 ]
      pulses: [
        '01010101010101010101010101010101010101011010101002'
        '01010101010101010101010101010101010101011010100102'
        '01010101010101010101010101010101010101010110101002'
        '01010101010101010101010101010101010101011010010102'
      ],
      values: [
         { id:0, unit:1, all:false, state:true }
         { id:0, unit:1, all:false, state:false}
         { id:0, unit:2, all:false, state:true }
         { id:0, unit:1, all:true , state:false}
      ]
    },
    {
      protocol: 'switch15'
      pulseLengths: [ 300, 914, 9624 ]
      pulses: [
        '01101001011001100110010110011010101001011010101002'
        '01101001011001100110010110011010101001010110101002'
        '01101001011001100110010110011010101001011001101002'
        '01101001011001100110010110011010101001011001010102'
      ],
      values: [
         { id:414908, unit:1, all:false, state:true }
         { id:414908, unit:1, all:false, state:false}
         { id:414908, unit:2, all:false, state:true }
         { id:414908, unit:0, all:true , state:false }
      ]
    },
    {
      protocol: 'switch17'
      pulseLengths: [260, 2680, 1275, 10550],
      pulses: [
        '010200020002000002000200020200020002000200020000020200000202000200020002000200020002000200000200020200000200020200020002000002020003'
      ],
      values: [
         { id: 59748338, unit: 13, all:false, state: true }
      ]
    },
    {
      protocol: 'switch16'
      pulseLengths: [330, 1000, 10500]
      pulses: [
        '01010110011001100101011001100110011001100110101002'
        '01010110011001100101011001100110011001100110010102'
        '01010110011001100110010101100110011001100110101002'
        '01010110011001100110010101100110011001100110010102'
        '01010110011001100110011001100110011001100110101002'
        '01010110011001100110011001010110011001100110010102'
        '01100101011001100101011001100110011001100110101002'
        '01100101011001100101011001100110011001100110010102'
        '01100101011001100110011001100110011001100110101002'
        '01100101011001100110011001010110011001100110010102'
      ],
      values: [
         { id:'A', unit:1, state:true }
         { id:'A', unit:1, state:false}
         { id:'A', unit:2, state:true }
         { id:'A', unit:2, state:false }
         { id:'A', unit:3, state:true }
         { id:'A', unit:3, state:false}
         { id:'B', unit:1, state:true }
         { id:'B', unit:1, state:false }
         { id:'B', unit:3, state:true }
         { id:'B', unit:3, state:false }
      ]
    },
    {
      protocol: 'switch21'
      pulseLengths: [204, 328, 1348, 10320],
      pulses: [
        '010201010101010202010201010101010101010201020101010201010202010201010101010101020101020101020101020101010101020102020102010101010201010101020103'
        '010101020101010201010101020102010101010201020101010102010202010201010101010101020101020101020101020101010101020102020102010101010201010101020103'
      ],
      values: [
         { remoteCode: 0xF150FC, unitCode: 0, state: true }
         { remoteCode: 0xF150FC, unitCode: 0, state: false }
      ]
    },
    {
      protocol: 'switch22'
      pulseLengths: [376, 1144, 11720]
      pulses: [
        '01100110101010101001100101010101101010010101011002'
        '01100110101010101001100101010101101010010101100102'
        '01100110101010101001100101010101101010010110010102'
        '01100110101010101001100101010101101010011001010102'
      ],
      values: [
        { id: 656881, command: 'A' }
        { id: 656881, command: 'B' }
        { id: 656881, command: 'C' }
        { id: 656881, command: 'D' }
      ]
    },
    {
      protocol: 'switch23'
      pulseLengths: [356, 716, 15728]
      pulses: [
        '00110011001100110011010100110011001012'
        '00110011001100110011010100110011010012'
        '00110011001100110011010100110010101102'
        '00110011001100110011010100110010110102'
      ],
      values: [
        { id: 10914, command: 'C' }
        { id: 10914, command: 'D' }
        { id: 10914, command: 'A' }
        { id: 10914, command: 'B' }
      ]
    },
    {
      protocol: 'switch24'
      pulseLengths: [504, 1024, 6120]
      pulses: [
        '01101010010101011010101010011010100101010101011002'
      ],
      values: [
        { houseCode: 17, unitCode: 1, state: true }
      ]
    },
    {
      protocol: 'switch25'
      pulseLengths: [350, 880, 10970]
      pulses: [
        '101010101010101010101010101010100101010101010101011010100110011002'
        '101010101010101010101010101010100101010101010101011010100101101002'
        '101010101010101010101010101010100101010101010101011001101010011002'
        '101010101010101010101010101010100101010101010101011001101001101002'
        '101010101010101010101010101010100101010101010101010110101010011002'
        '101010101010101010101010101010100101010101010101010110101001101002'
        '101010101010101010101010101010100101010101010101011010011010011002'
        '101010101010101010101010101010100101010101010101011010011001101002'
        '101010101010101010101010101010100101010101010101010101010110011002'
        '101010101010101010101010101010100101010101010101010101010101101002'
      ],
      values: [
        { state: true, unitCode: 14 }
        { state: false, unitCode: 14 }
        { state: true, unitCode: 11 }
        { state: false, unitCode: 11 }
        { state: true, unitCode: 7 }
        { state: false, unitCode: 7 }
        { state: true, unitCode: 13 }
        { state: false, unitCode: 13 }
        { state: true, unitCode: 0 }
        { state: false, unitCode: 0 }
      ]
    },
    {
      protocol: 'switch26'
      pulseLengths: [480, 1476, 15260]
      pulses: [
        '01010110011001100110010101100110011001100110101002'
        '01010110011001100110011001010110011001100110101002'
        '01010110011001100110011001010110011001100110010102'
      ],
      values: [
        { channel: 'A', unit: '3', state: true }
        { channel: 'A', unit: '4', state: true }
        { channel: 'A', unit: '4', state: false }
      ]
    },
    {
      protocol: 'switch27'
      pulseLengths: [325, 972, 10130]
      pulses: [
        '01100110011001100101011001100110011001100110101002'
        '01100110010101100101011001100110011001100110101002'
        '01100110011001010101011001100110011001100110101002'
      ],
      values: [
        { channel: 'A', unit: '1', state: true }
        { channel: 'C', unit: '1', state: true }
        { channel: 'D', unit: '1', state: true }
      ]
    },
    {
      protocol: 'switch28'
      pulseLengths: [310, 524, 1287, 13042]
      pulses: [
        '02020221020202210202022102210221022102020202212103'
        '02020221020202210202022102210221022102022121020203'
        '02020221020202210202022102210221022102020202020203'
      ],
      values: [
        { id: 11316396, unit: 26213, command: 'on' }
        { id: 11316396, unit: 26213, command: 'off' }
        { id: 11316396, unit: 26213, command: 'both' }
      ]
    },
    {
      protocol: 'switch29'
      pulseLengths: [404, 804, 4028]
      pulses: [
                '00101011101010101101001010101010111000110010101010110010101011001011010102'
                '00101011101010101101001010101010111000110010101010101011001011001010110012'
                '00101011101010101101001010101010111000110010101011001010101011001100110102'
                '00101011101010101101001010101010111000110010101010101100101011001010101102'
                '00101011101010101101001010101010111000110010101011010010101011001101010102'
                '00101011101010101101001010101010111000110010101011001100101011001100101102'
                '00101011101010101101001010101010111000110010101011010100101011001101001102'
      ],
      values: [
        { id: 5723557, unit: 5621333, command: "arm" }
        { id: 5723557, unit: 5621333, command: "panic" }
        { id: 5723557, unit: 5621333, command: "disarm" }
        { id: 5723557, unit: 5621333, command: "home" }
        { id: 5723557, unit: 5621333, command: "grp1" }
        { id: 5723557, unit: 5621333, command: "grp2" }
        { id: 5723557, unit: 5621333, command: "grp3" }
      ]
    },
    {
      protocol: 'switch30'
      pulseLengths: [520, 1468, 13312]
      pulses: [
        '01010101010110100101101001001110101001010101010102'
        '01010101010110100101101001001110010101011010010102'
        '01010101010110100101101001001110010101010101101002'
        '01010101010110100101101001001110010110100101010102'
      ],
      values: [
        { id: 21850, unit: 23118, command: 'arm' }
        { id: 21850, unit: 23118, command: 'dis' }
        { id: 21850, unit: 23118, command: 'byp' }
        { id: 21850, unit: 23118, command: 'sos' }
      ]
    },
    {
      protocol: 'switch31'
      pulseLengths: [452, 1336, 3392, 10124],
      pulses: [
        '0000220100010101000000010101000001000100010000000101010000000101000100010000000001010103'
        '0000220100010101000000010101000001000100010000000101010000000101000100000101010100000003'
        '0000220100010101000000010101000001000100010000000101010000000101000100000100000100010103'
        '0000220100010101000000010101000001000100010000000101010000000101000100010001010001000003'
        '0000220100010101000000010101000001000100010000000101010000000101000100010100000000010103'
        '0000220100010101000000010101000001000100010000000101010000000101000100000001010101000003'
        '0000220100010101000000010101000001000100010000000101010000000101000100000001000101000103'
        '0000220100010101000000010101000001000100010000000101010000000101000100010100010000010003'
        '0000220100010101000000010101000001000100010000000101010000000101000100010001000001000103'
        '0000220100010101000000010101000001000100010000000101010000000101000100000100010100010003'
      ],
      values: [
        { id: 47333, channel: 1, state: true, all: false }
        { id: 47333, channel: 1, state: false, all: false }
        { id: 47333, channel: 2, state: true, all: false }
        { id: 47333, channel: 2, state: false, all: false }
        { id: 47333, channel: 3, state: true, all: false }
        { id: 47333, channel: 3, state: false, all: false }
        { id: 47333, channel: 4, state: true, all: false }
        { id: 47333, channel: 4, state: false, all: false }
        { id: 47333, channel: 5, state: true, all: true }
        { id: 47333, channel: 5, state: false, all: true }
      ]
    },
    {
      protocol: 'switch32'
      pulseLengths: [440, 1300, 13488],
      pulses: [
        '01010110011001100101011001100110011001100110011002'
        '01010110011001100101011001100110011001100110010102'
        '01010110011001100110010101100110011001100110011002'
        '01010110011001100110010101100110011001100110010102'
        '01010110011001100110011001010110011001100110011002'
        '01010110011001100110011001010110011001100110010102'
        '01010110011001100110011001100101011001100110011002'
        '01010110011001100110011001100101011001100110010102'
        '01100101011001100101011001100110011001100110011002'
      ],
      values: [
        { systemCode: 1, programCode: 1, state: true }
        { systemCode: 1, programCode: 1, state: false }
        { systemCode: 1, programCode: 2, state: true }
        { systemCode: 1, programCode: 2, state: false }
        { systemCode: 1, programCode: 3, state: true }
        { systemCode: 1, programCode: 3, state: false }
        { systemCode: 1, programCode: 4, state: true }
        { systemCode: 1, programCode: 4, state: false }
        { systemCode: 2, programCode: 1, state: true }
      ]
    },
    {
      protocol: 'rolling1'
      pulseLengths: [500, 1000, 3000, 7250],
      pulses: [
        '01101010100101011001101010010110100110100101100123'
        '01101010011010011010011010010101100110011010100123'
        '01101010011010011010011010010101100110011010010123'
      ],
      values: [
         { code: "011110001011100110110010"}
         { code: "011101101101100010101110"}
         { code: "011101101101100010101100"}
      ]
    },
    {
      protocol: 'doorbell1'
      pulseLengths: [ 217, 648, 6696 ],
      pulses: [
        '01101010011001100110011010101010101010101010101002'
      ],
      values: [
         { id: 1361, unit: 0, state: true }
      ]
    },
    {
      protocol: 'doorbell3'
      pulseLengths: [ 300, 580, 10224 ],
      pulses: [
        '00101010101010101100110012'
        '01010010101010101100110012'
        '00110010101010101100110012'
        '01010101001010101100110012'
        '00110101001010101100110012'
        '01001101001010101100110012'
        '00101101001010101100110012'
        '01001100101010101100110012'
        '00101100101010101100110012'
        '01010100101010101100110012'
        '00110100101010101100110012'
        '01010011001010101100110012'
        '00110011001010101100110012'
        '01001011001010101100110012'
        '00101011001010101100110012'
        '01001010101010101100110012'
      ],
      values: [
         { id:  0, unit: 10 }
         { id: 12, unit: 10 }
         { id:  4, unit: 10 }
         { id: 15, unit: 10 }
         { id:  7, unit: 10 }
         { id: 11, unit: 10 }
         { id:  3, unit: 10 }
         { id: 10, unit: 10 }
         { id:  2, unit: 10 }
         { id: 14, unit: 10 }
         { id:  6, unit: 10 }
         { id: 13, unit: 10 }
         { id:  5, unit: 10 }
         { id:  9, unit: 10 }
         { id:  1, unit: 10 }
         { id:  8, unit: 10 }
      ]
    },
    {
      protocol: 'contact1'
      pulseLengths: [268, 1282, 2632, 10168]
      pulses: [
        '0200010001010001000001000100010100010000010100010001000100010000010100000100010001010001000001010001000001000101000100000100010100000101000001000103'
        '020001000101000100000100010001010001000001010001000100010001000001010000010001000101000100000101000100000100010001010000010001010003'
      ],
      values: [
        { id: 13040182, all: false, contact: false, unit: 9 }
        { id: 13040182, all: false, contact: true, unit: 9 }
      ]
    },
    {
      protocol: 'contact2'
      pulseLengths: [295, 886, 9626]
      pulses: [
        '10010110100101011010101010011001010101011001010102'
        '10010110100110011010010101101001010101011001010102'
     ],
      values: [
        { id: 421983, contact: false }
        { id: 414623, contact: false }
      ]
    },
    {
      protocol: 'contact4'
      pulseLengths: [468, 1364, 14096]
      pulses: [
        '10101001100110011001011010100101010101011001100102'
        '10101001100110011001011010100101010101011010100102'
        '10101001100110011001011010100101010101010110100102'
      ],
      values: [
        { id: 960960, contact: false, lowBattery: false }
        { id: 960960, contact: true, lowBattery: false }
        { id: 960960, contact: true, lowBattery: true }
      ]
    },
    {
      protocol: 'led1'
      pulseLengths: [ 350, 1056, 10904 ]
      pulses: [
        '01100110100101011001100110101001010110010101011002'
        '01011010010101100110011010101001010110010101011002'
        '01100110100101011001100110101001010110010110010102'
        '01100110100101011001100110101001010110010101100102'
     ],
      values: [
        { id: 22702, command: "on/off" }
        { id: 12638, command: "on/off" }
        { id: 22702, command: "up" }
        { id: 22702, command: "down" }
      ]
    },
    {
      protocol: 'led2'
      pulseLengths: [ 434, 1227, 13016 ]
      pulses: [
        '01010110101001101010100110011001010101100101011002'
        '01010110101001101010100110011001010101011001011002'
        '01010110101001101010100110011001010101010110101002'
        '01010110101001101010100110011001010101010101011002'
        '01010110101001101010100110011001010110010101011002'
     ],
      values: [
        { id: 7658, command: "mode-" }
        { id: 7658, command: "25%" }
        { id: 7658, command: "100%" }
        { id: 7658, command: "on/off" }
        { id: 7658, command: "code:00100001" }
      ]
    },
    {
      protocol: 'led4'
      pulseLengths: [ 346, 966, 9476 ]
      pulses: [
        '01010101010110100101011010100101100101010110011102'
        '01010101010110100101011010100101100101010101101102'
        '01010101010110100101011010100101100101010110100102'
        '01010101010110100101011010100101010101101010011102'
        '01010101010110100101011010100101010101010110010102'
     ],
      values: [
        { id: 796, command: "on/off" }
        { id: 796, command: "bright+" }
        { id: 796, command: "color+" }
        { id: 796, command: "code:00011101" }
        { id: 796, command: "code:00000100" }
      ]
    },
    {
      protocol: 'shutter3'
      pulseLengths: [ 366, 736, 1600, 5204, 10896 ]
      pulses: [
        '3210010110010101010110011010011010010110100101011001011001100101101010010110100104'
        '3210011010100110010101101001010110011010011001100110010101010101101010010110100104'
      ],
      values: [
        { id: 151368466, channel: 9, command: "program" }
        { id: 195237544, channel: 1, command: "program" }
      ]
    },
    {
      protocol: 'shutter4'
      pulseLengths: [ 352, 712, 1476, 5690 ]
      pulses: [
        '3201010110010101100101100101010101100101101010100101011001010101010101011001010113'
        '3201010110010101100101100101010101100101101010100101011001010110100110011001100113'
        '3201010110010101100101100101010101100101101010100101011001011001100101101010100103'
        '3201011001010101010110010101010101010110100101011001100101100101100101011001010113'
     ],
      values: [
        {id:17959394,channel:0,all:true,command:"up"}
        {id:17959394,channel:3,all:false,command:"stop"}
        {id:17959394,channel:5,all:false,command:"down"}
        {id:33817364,channel:9,all:false,command: 'up'}
      ]
    }
    {
      protocol: 'shutter5'
      pulseLengths: [ 160, 270, 665, 6856 ]
      pulses: [
        '02210202022102022121022102212121020221212102020203'
        '02210202022102022121022102212121020221210202210203'
        '02210202022102022121022102212121020221210221020203'
     ],
      values: [
        { id: 281971, command: "stop" }
        { id: 281971, command: "up" }
        { id: 281971, command: "down" }
       ]
    }
  ]

  runTest = ( (t) ->
    it "#{t.protocol} should decode the pulses", ->
      for pulses, i in t.pulses
        results = controller.decodePulses(t.pulseLengths, pulses)
        assert(results.length >= 1, "pulse #{pulses} of #{t.protocol} should be detected.")
        result = null
        for r in results
          if r.protocol is t.protocol
            result = r
            break
        assert(result, "pulse #{pulses} of #{t.protocol} should be detected as #{t.protocol}.")
        assert.deepEqual(result.values, t.values[i],
        "Expected values do not match actual: " + JSON.stringify(t.values[i]))
  )

  runTest(t) for t in tests

  it "should decode fixable pulses", ->
    pulseLengths =[ 258, 401, 1339, 2715, 10424 ]
    pulses = '030002000202000200000202000002020000020002020000020002020000020201020000020200020000020201020002000200000200020002000200020002000204'
    results = controller.decodePulses(pulseLengths, pulses)
    assert(results.length >= 1, "fixable pulses should be fixed.")


describe '#compressTimings()', ->
  tests = [
    {
      protocol: 'switch2'
      timings: [
        [ 288, 972, 292, 968, 292, 972, 292, 968, 292, 972, 920, 344, 288, 976, 920, 348,
          284, 976, 288, 976, 284, 976, 288, 976, 288, 976, 916, 348, 284, 980, 916, 348,
          284, 976, 920, 348, 284, 976, 920, 348, 284, 980, 280, 980, 284, 980, 916, 348,
          284, 9808
        ],
        [
          292, 968, 292, 972, 292, 972, 292, 976, 288, 976, 920, 344, 288, 976, 920, 348,
          284, 976, 288, 976, 288, 976, 284, 980, 284, 976, 920, 348, 284, 976, 916, 352,
          280, 980, 916, 352, 280, 980, 916, 348, 284, 980, 284, 976, 284, 984, 912, 352,
          280, 9808
        ],
        [
          292, 976, 288, 972, 292, 972, 292, 920, 288, 976, 920, 344, 288, 980, 916, 344,
          288, 980, 284, 980, 284, 972, 288, 980, 284, 976, 920, 344, 288, 976, 916, 352,
          280, 980, 916, 348, 284, 980, 916, 348, 284, 980, 284, 976, 288, 976, 916, 352,
          280, 9804
        ],
        [
          288, 972, 292, 968, 296, 972, 296, 976, 288, 976, 920, 344, 288, 976, 920, 344,
          292, 972, 288, 976, 288, 976, 284, 976, 288, 976, 920, 344, 288, 976, 920, 344,
          284, 980, 916, 348, 284, 980, 916, 348, 284, 980, 284, 976, 288, 980, 912, 352,
          280, 9808
        ]
      ]
      results: [
        {
          buckets: [ 304, 959, 9808 ],
          pulses: '01010101011001100101010101100110011001100101011002'
        }
        {
          buckets: [ 304, 959, 9808 ],
          pulses: '01010101011001100101010101100110011001100101011002'
        }
        {
          buckets: [ 304, 957, 9804 ],
          pulses: '01010101011001100101010101100110011001100101011002'
        }
        {
          buckets: [ 304, 959, 9808 ],
          pulses: '01010101011001100101010101100110011001100101011002'
        }
      ]
    },
    {
      protocol: 'switch4'
      timings: [
        [
          295, 1180, 295, 1180, 295, 1180, 1180, 295, 295, 1180, 295, 1180, 295, 1180, 1180, 295,
          295, 1180, 1180, 295, 295, 1180, 1180, 295, 295, 1180, 1180, 295, 295, 1180, 1180, 295,
          295, 1180, 295, 1180, 295, 1180, 1180, 295, 295, 1180, 1180, 295, 295, 1180, 1180, 295,
          295, 11210
        ]
      ]
      results: [
        {
          buckets: [ 295, 1180, 11210 ],
          pulses: '01010110010101100110011001100110010101100110011002'
        }
      ]
    }
  ]

  runTest = ( (t) ->
    it 'should compress the timings', ->
      for timings, i in t.timings
        result = controller.compressTimings(timings)
        assert.deepEqual(result, t.results[i])
  )

  runTest(t) for t in tests

describe '#encodeMessage()', ->
  tests = [
    {
      protocol: 'switch1'
      message: { id: 9390234, all: false, state: true, unit: 0 }
      pulses: '020001000101000001000100010100010001000100000101000001000101000001000100010100000100010100010000010100000100010100000100010001000103'
    },
    {
      protocol: 'switch2'
      message: { houseCode: 25, unitCode: 16, state: true }
      pulses: '01010101011001100101010101100110011001100101011002'
    },
    {
      protocol: 'switch5'
      message: { id: 465695, unit: 2, all: false, state: on }
      pulses: '10010101101010010110010110101001010101011010011002'
    },
    {
      protocol: 'switch6'
      message: {systemcode: 15, programcode: 2, state: true }
      pulses: '10101010101010100110011001010110011001100110010102'
    },
    {
      protocol: 'switch7'
      message: {id: 7, unit: 3, state: true }
      pulses: '01010101010101100101010101010110011001100110011002'
    },
    {
      protocol: 'switch8'
      message: {systemcode: 30, programcode: 'C3', state: true }
      pulses: '01010101010101010110011001101010010101010101101002'
    },
    {
      protocol: 'switch9'
      message: {id: 2472, unit: 65, state: true }
      pulses: '0110100101100110011010101001101010101001011012'
    },
    {
      protocol: 'switch10'
      message: {id:3162089194, unit:35, all:false, state:false }
      pulses: '01010000000101010100000100010101010000000101010100000101000100000101000101010001000100010001010001000101000000010102'
    },
    {
      protocol: 'switch12'
      message: {id: 9983, unit: 1, state: true }
      pulses: '1202021212021212121212121212021212121212121212121203'
    },
    {
      protocol: 'switch13'
      message: { id:1472, unit:0, all:false, state:true,  dimm:false}
      pulses: '001100110101001010101010101010110010101102'
    },
    {
      protocol: 'switch14'
      message: { id:0, unit:4, all:false, state:false}
      pulses: '01010101010101010101010101010101010101010101100102'
    },
    {
      protocol: 'switch15'
      message: { id:414908, unit:1, all:false, state:true }
      pulses: '01101001011001100110010110011010101001011010101002'
    },
    {
      protocol: 'switch16'
      message: { id:'A', unit:2, state:false }
      pulses: '01010110011001100110010101100110011001100110010102'
    },
    {
      protocol: 'switch21'
      message: { remoteCode: 0xF150FC, unitCode: 0, state: true }
      pulses: '010101010102010201010101020102010101010201020101010201010202010201010101010101020101020101020101020101010101020102020102010101010201010101020103'
    },
    {
      protocol: 'switch24'
      message: { houseCode: 17, unitCode: 1, state: true }
      pulses: '01101010010101011010100110010110100101010101011002'
    },
    {
      protocol: 'switch25'
      message: { unitCode: 14, state: true }
      pulses: '101010101010101010101010101010100101010101010101011010100110011002'
    },
    {
      protocol: 'switch29'
      message: { id: 5723557, unit: 5621333, command: 'panic' }
      pulses: '00101011101010101101001010101010111000110010101010101011001011001010110012'
    },
    {
      protocol: 'switch30'
      message: { id: 21850, unit: 23118, command: 'arm' }
      pulses: '01010101010110100101101001001110101001010101010102'
    },
    { 
      protocol: 'switch31'
      message: { all: false, channel: 1, id: 47333, state: true }
      pulses: '0000220100010101000000010101000001000100010000000101010000000101000100010000000001010103'
    },
    {
      protocol: 'switch32'
      message: { systemCode: 1, programCode: 1, state: true }
      pulses: '01010110011001100101011001100110011001100110011002'
    },
    {
      protocol: 'led3'
      message: {id:14152, command:"cyan" }
      pulses: '01011010011010100110010110010101010101100110010102'
    },
    {
      protocol: 'led4'
      message: {id:796, command:"on/off" }
      pulses: '01010101010110100101011010100101100101010110011002'
    },
    {
      protocol: 'doorbell1'
      message: { id: 1361, unit: 0, state: true }
      pulses: '01101010011001100110011010101010101010101010101002'
    },
    {
      protocol: 'rolling1'
      message: {
        codeOn: [
          "011111110000111001011100",
          "011101101101100010101100",
          "011111011110001001101100",
          "011110011010111100011100"
        ],
        codeOff: [
          "011110001011100110111100",
          "011110101001110001111100",
          "011100010001011100101100",
          "011101110011101010001100"
        ],
        state: true }
      pulses: '01101010101010100101010110101001011001101010010123'
    },
    {
      protocol: 'shutter3'
      message: { id: 151368466, channel: 9, command: "program" }
      pulses: '3210010110010101010110011010011010010110100101011001011001100101101010010110100104'
    }
    {
      protocol: 'shutter4'
      message: {id:17959394,channel:0,all:true,command:"up"}
      pulses: '3201010110010101100101100101010101100101101010100101011001010101010101011001010113'
    }
    {
      protocol: 'shutter5'
      message: { id: 281971, command: "down" }
      pulses: '02210202022102022121022102212121020221210221020203'
    }
  ]

  runTest = ( (t) ->
    it "should create the correct pulses for #{t.protocol}", ->
      result = controller.encodeMessage(t.protocol, t.message)
      assert.equal result.pulses, t.pulses
  )

  runTest(t) for t in tests


describe '#fixPulses()', ->
  tests = [
    {
      pulseLengths: [ 258, 401, 1339, 2715, 10424 ],
      pulses: '030002000202000200000202000002020000020002020000020002020000020201020000020200020000020201020002000200000200020002000200020002000204'
      result: {
        pulseLengths: [ 329, 1339, 2715, 10424 ],
        pulses: '020001000101000100000101000001010000010001010000010001010000010100010000010100010000010100010001000100000100010001000100010001000103'
      }
    },
    {
      pulseLengths: [ 239, 320, 1337, 2717, 10359 ],
      pulses: '030002000202000201010202010002020101020102020101020102020101020201020101020201020101020201020102010201010201020102010201020112000204'
      result: {
        pulseLengths: [ 279, 1337, 2717, 10359 ],
        pulses: '020001000101000100000101000001010000010001010000010001010000010100010000010100010000010100010001000100000100010001000100010001000103'
      }
    }
  ]

  runTest = ( (t) ->
    it "should fix the pulses", ->
      result = controller.fixPulses(t.pulseLengths, t.pulses)
      assert.deepEqual result.pulseLengths, t.result.pulseLengths
      assert.equal result.pulses, t.result.pulses
  )

  runTest(t) for t in tests

  it "should not change correct pulses", ->
    pulseLengths = [ 279, 1337, 2717, 10359 ]
    pulses = '020001000101000100000101000001010000010001010000010001010000010100010000010100010000010100010001000100000100010001000100010001000103'
    result = controller.fixPulses(pulseLengths, pulses)
    assert(result is null)



