quelink-mg 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 65d82d1ee48bd09561636c3a37c45d215f83c859b5b0973d53fab2dab2000e99
4
+ data.tar.gz: 3b072ed25d29451bed4b73b23d1a97953b0839351cdbeac1de61c71d30d89f13
5
+ SHA512:
6
+ metadata.gz: a36b701c8db093fa3439ae34fa0ed73d34e8e579342d069eb626824bf32e4bd8c01f3698b5cd2f703aa9c7189e12f3badedeab517b3ea9281112ece9eec642f8
7
+ data.tar.gz: a8807739c2796ce72d53fc5c22f13238a15459b3e7d5734679d86e7429ef7c906ee33a20e9f796a0b10aed2af2be9e0c0fbf95cf0de81d50d2d3bf320b9de558
data/.rubocop.yml ADDED
@@ -0,0 +1,21 @@
1
+ require:
2
+ - rubocop-rspec
3
+ AllCops:
4
+ DisplayCopNames: true
5
+ NewCops: enable
6
+ TargetRubyVersion: 3.1
7
+ Style/Documentation:
8
+ Enabled: false
9
+ Metrics/MethodLength:
10
+ Max: 15
11
+ Metrics/BlockLength:
12
+ Max: 40
13
+ Gemspec/DevelopmentDependencies:
14
+ Enabled: false
15
+ RSpec/MultipleExpectations:
16
+ Enabled: false
17
+ RSpec/ExampleLength:
18
+ Max: 20
19
+ Layout/LineLength:
20
+ Exclude:
21
+ - spec/quelink_mg/resp/*_spec.rb
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,85 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ quelink-mg (0.1.0)
5
+ activesupport (~> 7.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activesupport (7.0.7)
11
+ concurrent-ruby (~> 1.0, >= 1.0.2)
12
+ i18n (>= 1.6, < 2)
13
+ minitest (>= 5.1)
14
+ tzinfo (~> 2.0)
15
+ ast (2.4.2)
16
+ base64 (0.1.1)
17
+ coderay (1.1.3)
18
+ concurrent-ruby (1.2.2)
19
+ diff-lcs (1.5.0)
20
+ i18n (1.14.1)
21
+ concurrent-ruby (~> 1.0)
22
+ json (2.6.3)
23
+ language_server-protocol (3.17.0.3)
24
+ method_source (1.0.0)
25
+ minitest (5.19.0)
26
+ parallel (1.23.0)
27
+ parser (3.2.2.3)
28
+ ast (~> 2.4.1)
29
+ racc
30
+ pry (0.14.2)
31
+ coderay (~> 1.1)
32
+ method_source (~> 1.0)
33
+ racc (1.7.1)
34
+ rainbow (3.1.1)
35
+ regexp_parser (2.8.1)
36
+ rexml (3.2.6)
37
+ rspec (3.12.0)
38
+ rspec-core (~> 3.12.0)
39
+ rspec-expectations (~> 3.12.0)
40
+ rspec-mocks (~> 3.12.0)
41
+ rspec-core (3.12.2)
42
+ rspec-support (~> 3.12.0)
43
+ rspec-expectations (3.12.3)
44
+ diff-lcs (>= 1.2.0, < 2.0)
45
+ rspec-support (~> 3.12.0)
46
+ rspec-mocks (3.12.6)
47
+ diff-lcs (>= 1.2.0, < 2.0)
48
+ rspec-support (~> 3.12.0)
49
+ rspec-support (3.12.1)
50
+ rubocop (1.56.0)
51
+ base64 (~> 0.1.1)
52
+ json (~> 2.3)
53
+ language_server-protocol (>= 3.17.0)
54
+ parallel (~> 1.10)
55
+ parser (>= 3.2.2.3)
56
+ rainbow (>= 2.2.2, < 4.0)
57
+ regexp_parser (>= 1.8, < 3.0)
58
+ rexml (>= 3.2.5, < 4.0)
59
+ rubocop-ast (>= 1.28.1, < 2.0)
60
+ ruby-progressbar (~> 1.7)
61
+ unicode-display_width (>= 2.4.0, < 3.0)
62
+ rubocop-ast (1.29.0)
63
+ parser (>= 3.2.1.0)
64
+ rubocop-capybara (2.18.0)
65
+ rubocop (~> 1.41)
66
+ rubocop-rspec (2.21.0)
67
+ rubocop (~> 1.33)
68
+ rubocop-capybara (~> 2.17)
69
+ ruby-progressbar (1.13.0)
70
+ tzinfo (2.0.6)
71
+ concurrent-ruby (~> 1.0)
72
+ unicode-display_width (2.4.2)
73
+
74
+ PLATFORMS
75
+ x86_64-linux
76
+
77
+ DEPENDENCIES
78
+ pry (~> 0.13)
79
+ quelink-mg!
80
+ rspec (~> 3.9)
81
+ rubocop (~> 1.0)
82
+ rubocop-rspec (~> 2.2)
83
+
84
+ BUNDLED WITH
85
+ 2.4.7
data/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # quelink-mg
2
+ Management of commands sent or received from QUELINK-300 device serie. Tested with MG-310 and MG-320
3
+
4
+ ## Instalation
5
+
6
+ The quelink-mg gem is available at rubygems.org. You can install with:
7
+
8
+ `gem install quelink-mg`
9
+
10
+ Alternatively, you can install the gem with bundler:
11
+
12
+ \# Gemfile
13
+
14
+ `gem 'quelink-mg'`
15
+
16
+ After doing bundle install, you should have the gem installed in your bundle.
17
+
18
+ ## Development
19
+
20
+ Building gem locally (you can change file name, ofc):
21
+ gem build *.gemspec -o pkg/quelink-mg.gem
22
+
23
+ Installing:
24
+ gem install pkg/quelink-mg.gem
25
+
26
+
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QuelinkMg
4
+ module Ack
5
+ class Base
6
+ QUELINK_DATE_FORMAT = '%Y%m%d%H%M%S'
7
+
8
+ def initialize(response:)
9
+ @response = response
10
+ end
11
+
12
+ private
13
+
14
+ def float?(value)
15
+ !Float(value, exception: false).nil?
16
+ end
17
+
18
+ def integer?(value)
19
+ !Integer(value, exception: false).nil?
20
+ end
21
+
22
+ def date?(value)
23
+ date = DateTime.strptime(value, QUELINK_DATE_FORMAT)
24
+
25
+ !date.nil? && (date - DateTime.now).abs < 3 * 365
26
+ rescue Date::Error
27
+ false
28
+ end
29
+
30
+ def transform_with_timezone(value)
31
+ QuelinkMg.configuration.time_zone.strptime(value, QUELINK_DATE_FORMAT)
32
+ end
33
+
34
+ def unify_keys(hash)
35
+ hash.transform_values do |v|
36
+ if date?(v)
37
+ transform_with_timezone(v)
38
+ elsif integer?(v)
39
+ v.to_i
40
+ elsif float?(v)
41
+ v.to_f
42
+ else
43
+ v
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QuelinkMg
4
+ module Ack
5
+ class Gtbsi < Base
6
+ GTBSI_ACK_KEYS = %w[protocol_version unique_id device_name serial_number send_time count_number].freeze
7
+
8
+ def hash
9
+ unify_keys(GTBSI_ACK_KEYS.zip(@response.split(',')).to_h)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ class InvalidATGTBSIException < StandardError; end
4
+
5
+ module QuelinkMg
6
+ module At
7
+ class Base
8
+ def initialize(params:)
9
+ @params = params
10
+ end
11
+
12
+ private
13
+
14
+ def verify_params(acceptable_values, error)
15
+ acceptable_values.each do |k, v|
16
+ next if v.include?(@params.fetch(k, nil))
17
+
18
+ raise_error(k, error)
19
+ end
20
+ end
21
+
22
+ def raise_error(type, error)
23
+ raise error, "Wrong #{type}: #{@params}"
24
+ end
25
+
26
+ def reserved; end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QuelinkMg
4
+ module At
5
+ class Gtbsi < Base
6
+ def message
7
+ validate_values
8
+
9
+ "AT+GTBSI=#{joined_params}$"
10
+ end
11
+
12
+ private
13
+
14
+ GTBSI_VALID_PARAMS = %i[password lte_apn lte_apn_user_name ltn_apn_password gprs_apn gprs_apn_user_name
15
+ gprs_apn_password network_mode lte_mode apn_authentication_methods manual_netreg
16
+ reserved reserved reserved reserved serial_number].freeze
17
+
18
+ def joined_params
19
+ GTBSI_VALID_PARAMS.map { |method| @params.fetch(method, nil) }.join(',')
20
+ end
21
+
22
+ def validate_values
23
+ acceptable_values = {
24
+ network_mode: (0..3),
25
+ lte_mode: (0..3),
26
+ apn_authentication_methods: (0..3),
27
+ manual_netreg: (0..5)
28
+ }
29
+
30
+ verify_params(acceptable_values, InvalidATGTBSIException)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QuelinkMg
4
+ class Configuration
5
+ attr_accessor :time_zone
6
+
7
+ DEFAULT_ZONE = ActiveSupport::TimeZone.new('Europe/Warsaw')
8
+ def initialize
9
+ @time_zone = DEFAULT_ZONE
10
+ Time.zone = @time_zone
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QuelinkMg
4
+ module Resp
5
+ class Base
6
+ QUELINK_DATE_FORMAT = '%Y%m%d%H%M%S'
7
+
8
+ def initialize(response:)
9
+ @response = response
10
+ end
11
+
12
+ private
13
+
14
+ def float?(value)
15
+ !Float(value, exception: false).nil?
16
+ end
17
+
18
+ def integer?(value)
19
+ !Integer(value, exception: false).nil?
20
+ end
21
+
22
+ def date?(value)
23
+ date = DateTime.strptime(value, QUELINK_DATE_FORMAT)
24
+
25
+ !date.nil? && (date - DateTime.now).abs < 3 * 365
26
+ rescue Date::Error
27
+ false
28
+ end
29
+
30
+ def transform_with_timezone(value)
31
+ QuelinkMg.configuration.time_zone.strptime(value, QUELINK_DATE_FORMAT)
32
+ end
33
+
34
+ def unify_keys(hash)
35
+ hash.transform_values do |v|
36
+ if date?(v)
37
+ transform_with_timezone(v)
38
+ elsif integer?(v)
39
+ v.to_i
40
+ elsif float?(v)
41
+ v.to_f
42
+ else
43
+ v
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QuelinkMg
4
+ module Resp
5
+ class Gtfri < Base
6
+ GTFRI_RESP_KEYS = %w[protocol_version unique_id device_name report_id report_type number
7
+ gps_accuracy speed azimuth elevation longitude latitude gps_utc_time
8
+ mcc mnc lac cell_id odo_mileage battery_percentage send_time count_number].freeze
9
+
10
+ def hash
11
+ unify_keys(GTFRI_RESP_KEYS.zip(@response.split(',')).to_h)
12
+ end
13
+ end
14
+ end
15
+ end
data/lib/quelink_mg.rb ADDED
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pry'
4
+ require 'date'
5
+ require 'active_support'
6
+ require 'active_support/time_with_zone'
7
+ require 'active_support/core_ext/time/zones'
8
+
9
+ require File.expand_path('quelink-mg/at/base.rb', __dir__)
10
+ require File.expand_path('quelink-mg/at/gtbsi.rb', __dir__)
11
+ require File.expand_path('quelink-mg/resp/base.rb', __dir__)
12
+ require File.expand_path('quelink-mg/resp/gtfri.rb', __dir__)
13
+ require File.expand_path('quelink-mg/ack/base.rb', __dir__)
14
+ require File.expand_path('quelink-mg/ack/gtbsi.rb', __dir__)
15
+ require File.expand_path('quelink-mg/configuration.rb', __dir__)
16
+
17
+ module QuelinkMg
18
+ class << self
19
+ def configuration
20
+ @configuration ||= Configuration.new
21
+ end
22
+
23
+ def configure
24
+ yield(configuration)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'quelink-mg'
5
+ s.version = '0.1.0'
6
+ s.summary = 'Quelink devices command reader and writer'
7
+ s.description = 'Quelink devices command reader and writer'
8
+ s.authors = ['Stanislaw Zawadzki']
9
+ s.email = 'st.zawadzki@gmail.com'
10
+
11
+ s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
12
+ s.require_paths = ['lib']
13
+ s.license = 'MIT'
14
+ s.required_ruby_version = '>= 3.1'
15
+ s.add_dependency 'activesupport', '~> 7.0'
16
+ s.add_development_dependency 'pry', '~> 0.13'
17
+ s.add_development_dependency 'rspec', '~> 3.9'
18
+ s.add_development_dependency 'rubocop', '~> 1.0'
19
+ s.add_development_dependency 'rubocop-rspec', '~> 2.2'
20
+ # s.metadata['rubygems_mfa_required'] = 'true'
21
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe QuelinkMg::Ack::Gtbsi do
6
+ it 'parses valid response' do
7
+ response = 'D40102,868239051011356,,0040,20210816045509,004F'
8
+ parsed_response = described_class.new(response:).hash
9
+ expect(parsed_response['protocol_version']).to eq 'D40102'
10
+ expect(parsed_response['unique_id']).to eq 868_239_051_011_356
11
+ expect(parsed_response['send_time']).to eq Time.zone.strptime('20210816045509',
12
+ QuelinkMg::Resp::Base::QUELINK_DATE_FORMAT)
13
+ end
14
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe QuelinkMg::At::Gtbsi do
6
+ it 'creates command when params are valid' do
7
+ params =
8
+ {
9
+ password: 'qwerty',
10
+ lte_apn: 'https://apn.org/',
11
+ network_mode: 0,
12
+ lte_mode: 0,
13
+ apn_authentication_methods: 0,
14
+ manual_netreg: 0,
15
+ serial_number: 'ABFF'
16
+ }
17
+
18
+ expect(described_class.new(params:).message).to eq 'AT+GTBSI=qwerty,https://apn.org/,,,,,,0,0,0,0,,,,,ABFF$'
19
+ end
20
+
21
+ it 'raises error on missing params' do
22
+ expect { described_class.new(params: {}).message }.to raise_error(InvalidATGTBSIException)
23
+ end
24
+
25
+ it 'raises error on improper params' do
26
+ params =
27
+ {
28
+ password: 'qwerty',
29
+ lte_apn: 'https://apn.org/',
30
+ network_mode: 10,
31
+ lte_mode: 10,
32
+ apn_authentication_methods: 0,
33
+ manual_netreg: 0,
34
+ serial_number: 'ABFF'
35
+ }
36
+
37
+ expect { described_class.new(params:).message }.to raise_error(InvalidATGTBSIException)
38
+ end
39
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe QuelinkMg::Resp::Gtfri do
6
+ it 'parses valid response' do
7
+ response = 'C30204,860201061504521,,0,0,1,1,0.0,0,96.2,21.012847,52.200338,20230813061232,0260,0003,E31F,0447020D,,34,20230813061231,3E94'
8
+
9
+ parsed_response = described_class.new(response:).hash
10
+ expect(parsed_response).not_to eq({})
11
+ expect(parsed_response['send_time']).to eq Time.zone.strptime('20230813061231',
12
+ QuelinkMg::Resp::Base::QUELINK_DATE_FORMAT)
13
+ expect(parsed_response['gps_utc_time']).to eq Time.zone.strptime('20230813061232',
14
+ QuelinkMg::Resp::Base::QUELINK_DATE_FORMAT)
15
+ expect(parsed_response['longitude']).to eq 21.012847
16
+ expect(parsed_response['latitude']).to eq 52.200338
17
+ expect(parsed_response['unique_id']).to eq 860_201_061_504_521
18
+ expect(parsed_response['battery_percentage']).to eq 34
19
+ expect(parsed_response['device_name']).to eq ''
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/quelink_mg'
4
+
5
+ QuelinkMg.configure do |config|
6
+ config.time_zone = QuelinkMg::Configuration::DEFAULT_ZONE
7
+ end
8
+
9
+ RSpec.configure do |config|
10
+ config.expect_with :rspec do |expectations|
11
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
12
+ end
13
+
14
+ config.mock_with :rspec do |mocks|
15
+ mocks.verify_partial_doubles = true
16
+ end
17
+
18
+ config.shared_context_metadata_behavior = :apply_to_host_groups
19
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: quelink-mg
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Stanislaw Zawadzki
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-08-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '7.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '7.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.13'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.13'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.2'
83
+ description: Quelink devices command reader and writer
84
+ email: st.zawadzki@gmail.com
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - ".rubocop.yml"
90
+ - Gemfile
91
+ - Gemfile.lock
92
+ - README.md
93
+ - lib/quelink-mg/ack/base.rb
94
+ - lib/quelink-mg/ack/gtbsi.rb
95
+ - lib/quelink-mg/at/base.rb
96
+ - lib/quelink-mg/at/gtbsi.rb
97
+ - lib/quelink-mg/configuration.rb
98
+ - lib/quelink-mg/resp/base.rb
99
+ - lib/quelink-mg/resp/gtfri.rb
100
+ - lib/quelink_mg.rb
101
+ - quelink-mg.gemspec
102
+ - spec/quelink_mg/ack/gtbsi_spec.rb
103
+ - spec/quelink_mg/at/gtbsi_spec.rb
104
+ - spec/quelink_mg/resp/gtfri_spec.rb
105
+ - spec/spec_helper.rb
106
+ homepage:
107
+ licenses:
108
+ - MIT
109
+ metadata: {}
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '3.1'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubygems_version: 3.3.7
126
+ signing_key:
127
+ specification_version: 4
128
+ summary: Quelink devices command reader and writer
129
+ test_files: []