Module: PWN::SDR::Decoder::RTL433

Defined in:
lib/pwn/sdr/decoder/rtl433.rb

Overview

Generic ISM/keyfob/sensor decoder backed by rtl_433.

Covers the OOK/ASK/FSK device zoo on 300–315 / 390 / 433.92 / 868 / 902–928 MHz: car/garage keyfobs, TPMS, weather stations, utility meters, doorbells, alarm PIRs, etc. rtl_433 owns the SDR directly and emits one JSON object per decoded frame (-F json), which this module merges verbatim into the freq_obj log line.

Class Method Summary collapse

Class Method Details

.authorsObject

Author(s)

0day Inc. support@0dayinc.com



71
72
73
# File 'lib/pwn/sdr/decoder/rtl433.rb', line 71

public_class_method def self.authors
  "AUTHOR(S):\n  0day Inc. <support@0dayinc.com>\n"
end

.decode(opts = {}) ⇒ Object

Supported Method Parameters

PWN::SDR::Decoder::RTL433.decode( freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq' )



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/pwn/sdr/decoder/rtl433.rb', line 22

public_class_method def self.decode(opts = {})
  freq_obj = opts[:freq_obj]
  raise 'ERROR: :freq_obj is required' unless freq_obj.is_a?(Hash)

  hz       = PWN::SDR.hz_to_i(freq: freq_obj[:freq])
  gain     = freq_obj[:rf_gain]
  sdr_args = freq_obj[:sdr_args].to_s

  cmd = ['rtl_433', '-f', hz.to_s, '-F', 'json', '-M', 'level', '-M', 'protocol']
  cmd.push('-g', gain.to_s) if gain
  cmd.push('-d', sdr_args) unless sdr_args.empty?
  direct_cmd = Shellwords.join(cmd)

  PWN::SDR::Decoder::Base.run_pipeline(
    freq_obj: freq_obj,
    protocol: 'RTL433',
    required_bins: %w[rtl_433],
    direct_cmd: direct_cmd,
    line_match: /^\s*{/,
    parser: proc { |line| parse_line(line: line) }
  )
end

.helpObject

Display Usage for this Module



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/pwn/sdr/decoder/rtl433.rb', line 77

public_class_method def self.help
  puts "USAGE:
    #{self}.decode(
      freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq'
    )

    NOTE: Requires `rtl_433`. Owns the SDR directly (pass
          freq_obj[:sdr_args] like ':1' or 'driver=hackrf' to select
          a device other than the one GQRX is holding).

    #{self}.parse_line(line: '{\"model\":\"Acurite-Tower\",\"id\":1234,...}')

    #{self}.authors
  "
end

.parse_line(opts = {}) ⇒ Object

Supported Method Parameters

PWN::SDR::Decoder::RTL433.parse_line(line: '"time":"...","model":".."time":"...","model":"..."')



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/pwn/sdr/decoder/rtl433.rb', line 48

public_class_method def self.parse_line(opts = {})
  line = opts[:line].to_s
  h = begin
    JSON.parse(line, symbolize_names: true)
  rescue StandardError
    { unparsed: line }
  end
  out = { protocol: 'RTL433' }.merge(h)

  bits = []
  bits << out[:model].to_s if out[:model]
  bits << "id=#{out[:id]}" if out[:id]
  bits << "ch=#{out[:channel]}" if out[:channel]
  bits << "code=#{out[:code]}" if out[:code]
  bits << "cmd=#{out[:cmd] || out[:button]}" if out[:cmd] || out[:button]
  bits << "temp=#{out[:temperature_C]}C" if out[:temperature_C]
  bits << "rssi=#{out[:rssi]}" if out[:rssi]
  out[:summary] = bits.empty? ? line[0, 120] : bits.join(' ')
  out
end