class Itiscold

Constants

DataHeader
DeviceInfo
NULL_DATE
VERSION

Public Class Methods

new(tty) click to toggle source
# File lib/itiscold.rb, line 20
def initialize tty
  @tty = tty
end
open(filename, speed = 115200) click to toggle source
# File lib/itiscold.rb, line 11
def self.open filename, speed = 115200
  f = UART.open filename, speed

  temp = new f

  # Try reading the version a few times before giving up
  temp
end

Public Instance Methods

clear_data!() click to toggle source
# File lib/itiscold.rb, line 134
def clear_data!
  self.device_params = device_info
end
close() click to toggle source
# File lib/itiscold.rb, line 97
def close
  @tty.close
end
data_body(station, page) click to toggle source
# File lib/itiscold.rb, line 183
def data_body station, page
  buf = retry_comm(1) do
    @tty.write with_checksum([0x33, station, 0x2, page]).pack('C5')
    @tty.read
  end
  temps = buf.unpack("Cn#{(buf.bytesize - 2) / 2}C")
  temps.shift # header
  temps.pop   # checksum
  temps.map { |t| t / 10.0 }
end
data_header(station) click to toggle source
# File lib/itiscold.rb, line 171
def data_header station
  buf = retry_comm(1) do
    @tty.write with_checksum([0x33, station, 0x1, 0x0]).pack('C5')
    @tty.read 11
  end
  _, sample_count, start_time, check = buf.unpack 'CnA7C'

  check_checksum check, checksum(buf.bytes.first(buf.bytesize - 1))

  DataHeader.new sample_count, unpack_datetime(start_time)
end
device_info() click to toggle source
# File lib/itiscold.rb, line 44
def device_info
  val = nil

  loop do
    if @tty.wait_writable
      @tty.write with_checksum([0xCC, 0x00, 0x06, 0x00]).pack('C5')
    else
      raise "Couldn't open tty for writing"
    end

    if @tty.wait_readable(2)
      val = @tty.read 160
      break
    end
  end

  _,            # C set number
  station_no,   # C station number
  _,            # C
  model_no,     # C model number
  _,            # C
  rec_int_h,    # C record interval hour
  rec_int_m,    # C record interval min
  rec_int_s,    # C record interval sec
  upper_limit,  # n upper limit
  lower_limit,  # s> lower limit
  last_online,  # A7 (datetime)
  ws,           # C work status
  start_time,   # A7 (datetime)
  sb,           # C stop button
  _,            # C
  sample_count, # n number of records
  current_time, # A7 (datetime)
  user_info,    # A100
  number,       # A10
  delaytime,    # C
  tone_set,     # C
  alrm,         # C
  tmp_unit,     # C
  temp_calib,   # C temp calibration
  _,            # A6 padding
  check,        # C padding
  = val.unpack('C8ns>A7CA7CCnA7A100A10C5A6C')
  check_checksum check, checksum(val.bytes.first(val.bytesize - 1))
  DeviceInfo.new station_no, model_no,
    (rec_int_h * 3600 + rec_int_m * 60 + rec_int_s),
    upper_limit / 10.0, lower_limit / 10.0, unpack_datetime(last_online),
    work_status(ws), unpack_datetime(start_time), allowed_decode(sb),
    sample_count, unpack_datetime(current_time), user_info, number,
    delay_time_decode(delaytime), allowed_decode(tone_set), alrm, temp_unit_decode(tmp_unit),
    temp_calib / 10.0
end
device_params=(values) click to toggle source
# File lib/itiscold.rb, line 101
def device_params= values
  data = [
    0x33, # C
    values.station_number, # C
    0x05, 0x00,            # CC
  ] + split_time(values.sample_interval) + # CCC
  [
    (values.upper_limit * 10).to_i & 0xFFFF, # n
    (values.lower_limit * 10).to_i & 0xFFFF, # s>
    values.new_station_number || values.station_number, # C
    allowed_encode(values.stop_button), # C
    delay_time_encode(values.delay_time), # C
    allowed_encode(values.tone_set), # C
    values.alarm, # C
    temp_unit_encode(values.temp_unit), # C
    (values.temp_calibration * 10).to_i, # C
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00 # C6
  ]

  loop do
    if @tty.wait_writable
      @tty.write with_checksum(data).pack('CCCCCCCns>CCCCCCCC6C')
    else
      raise "Couldn't open tty for writing"
    end

    if @tty.wait_readable(2)
      @tty.read 3
      break
    end
  end
end
flush() click to toggle source
# File lib/itiscold.rb, line 210
def flush
  Termios.tcflush @tty, Termios::TCIOFLUSH
end
samples() click to toggle source
# File lib/itiscold.rb, line 194
def samples
  info    = device_info
  header  = data_header info.station_number
  records = header.sample_count
  page    = 0
  list    = []
  while records > 0
    samples = data_body info.station_number, page
    records -= samples.length
    list    += samples
    page    += 1
  end
  st = header.start_time
  list.map.with_index { |v, i| [st + (i * info.sample_interval), v] }
end
set_device_number(station_number, dev_number) click to toggle source
# File lib/itiscold.rb, line 138
def set_device_number station_number, dev_number
  str = dev_number.bytes.first(10)
  str.concat([0x00] * (10 - str.length))
  data = [ 0x33, station_number, 0x0b, 0x00 ] + str

  retry_comm(1) do
    @tty.write with_checksum(data).pack("C#{data.length + 1}")
    @tty.read 3
  end
end
set_device_time!(time = Time.now, station_number = device_info.station_number) click to toggle source
# File lib/itiscold.rb, line 160
def set_device_time! time = Time.now, station_number = device_info.station_number
  data = [0x33, station_number, 0x07, 0x00] + encode_datetime(time)

  retry_comm(1) do
    @tty.write with_checksum(data).pack("C4nC6")
    @tty.read 3
  end
end
set_user_info(info, station_number = device_info.station_number) click to toggle source
# File lib/itiscold.rb, line 149
def set_user_info info, station_number = device_info.station_number
  str = info.bytes.first(100)
  str.concat([0x00] * (100 - str.length))
  data = [ 0x33, station_number, 0x09, 0x00 ] + str

  retry_comm(1) do
    @tty.write with_checksum(data).pack("C#{data.length + 1}")
    @tty.read 3
  end
end

Private Instance Methods

allowed_decode(sb) click to toggle source
# File lib/itiscold.rb, line 275
def allowed_decode sb
  case sb
  when 0x13 then :permit
  when 0x31 then :prohibit
  else
    raise sb.to_s
  end
end
allowed_encode(sb) click to toggle source
# File lib/itiscold.rb, line 284
def allowed_encode sb
  case sb
  when :permit then 0x13
  when :prohibit then 0x31
  else
    raise sb.to_s
  end
end
check_checksum(expected, actual) click to toggle source
# File lib/itiscold.rb, line 302
def check_checksum expected, actual
  raise "invalid checksum #{expected} == #{actual}" unless expected == actual
end
checksum(list) click to toggle source
# File lib/itiscold.rb, line 321
def checksum list
  list.inject(:+) % 256
end
delay_time_decode(dt) click to toggle source
# File lib/itiscold.rb, line 253
def delay_time_decode dt
  case dt
  when 0x00 then 0
  when 0x01 then 30 * 60  # 30min in sec
  when 0x10 then 60 * 60  # 60min in sec
  when 0x11 then 90 * 60  # 90min in sec
  when 0x20 then 120 * 60 # 120min in sec
  when 0x21 then 150 * 60 # 150min in sec
  end
end
delay_time_encode(dt) click to toggle source
# File lib/itiscold.rb, line 264
def delay_time_encode dt
  case dt
  when 0        then 0x00
  when 30 * 60  then 0x01 # 30min in sec
  when 60 * 60  then 0x10 # 60min in sec
  when 90 * 60  then 0x11 # 90min in sec
  when 120 * 60 then 0x20 # 120min in sec
  when 150 * 60 then 0x21 # 150min in sec
  end
end
encode_datetime(time) click to toggle source
# File lib/itiscold.rb, line 313
def encode_datetime time
  [time.year, time.month, time.day, time.hour, time.min, time.sec]
end
retry_comm(times) { || ... } click to toggle source
# File lib/itiscold.rb, line 224
def retry_comm times
  x = nil
  loop do
    x = yield
    break if x || times == 0
    flush
    times -= 1
  end
  x
end
split_time(time_s) click to toggle source
# File lib/itiscold.rb, line 216
def split_time time_s
  h = time_s / 3600
  time_s -= (h * 3600)
  m = time_s / 60
  time_s -= (m * 60)
  [h, m, time_s]
end
temp_unit_decode(u) click to toggle source
# File lib/itiscold.rb, line 235
def temp_unit_decode u
  case u
  when 0x13 then 'F'
  when 0x31 then 'C'
  else
    raise u.to_s
  end
end
temp_unit_encode(u) click to toggle source
# File lib/itiscold.rb, line 244
def temp_unit_encode u
  case u
  when 'F' then 0x13
  when 'C' then 0x31
  else
    raise u.to_s
  end
end
unpack_datetime(bytes) click to toggle source
# File lib/itiscold.rb, line 308
def unpack_datetime bytes
  return if bytes == NULL_DATE
  Time.new(*bytes.unpack('nC5'))
end
with_checksum(list) click to toggle source
# File lib/itiscold.rb, line 317
def with_checksum list
  list + [checksum(list)]
end
work_status(ws) click to toggle source
# File lib/itiscold.rb, line 293
def work_status ws
  case ws
  when 0 then :not_started
  when 1 then :start
  when 2 then :stop
  when 3 then :unknown
  end
end