mqttopia 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rubocop.yml +39 -0
- data/CHANGELOG.md +5 -0
- data/MQTT_SUBSCRIPTIONS.md +135 -0
- data/README.md +142 -0
- data/Rakefile +16 -0
- data/TEST_README.md +57 -0
- data/lib/generators/mqttopia/install_generator.rb +18 -0
- data/lib/generators/templates/mqttopia_initializer.rb +26 -0
- data/lib/mqttopia/client.rb +140 -0
- data/lib/mqttopia/helpers/data_extractor.rb +23 -0
- data/lib/mqttopia/logger.rb +29 -0
- data/lib/mqttopia/serializers/test_debug.rb +17 -0
- data/lib/mqttopia/serializers/trip_metric.rb +58 -0
- data/lib/mqttopia/subscriptions/redirect.rb +33 -0
- data/lib/mqttopia/subscriptions/services/base.rb +16 -0
- data/lib/mqttopia/subscriptions/services/test_debug.rb +40 -0
- data/lib/mqttopia/subscriptions/services/trip_metrics.rb +45 -0
- data/lib/mqttopia/topics/services.rb +22 -0
- data/lib/mqttopia/version.rb +5 -0
- data/lib/mqttopia.rb +26 -0
- data/lib/tasks/initialize.rake +44 -0
- data/mqttopia.gemspec +49 -0
- data/sig/mqttopia.rbs +4 -0
- metadata +223 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6dcdb52227984d43667ef297e1740a96329a28931140f2c2760a6446cf5ee31a
|
4
|
+
data.tar.gz: 8d1ba1e116657ae18027c2686599476b859600de42fec69c1e938f23a6c89f05
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b8ae4365a041299e9e4e4e2e43c75cdb4ca5cf8406fc451e0e95a47ccc834ccf21998c76f909c8bb924922588b0eaecedaaa7689ba9ad8881b3d8d3fa0ff6823
|
7
|
+
data.tar.gz: 2bd8bef90f21419e6fdf594eb4c81ad920bb11eac3bbfd74c081280b9d0e866bb32802cda0b90f0b71804521127195af9e6b0e0ca36035093c917e6fd6b7fef6
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.7
|
3
|
+
Include:
|
4
|
+
- 'app/**/*.rb'
|
5
|
+
- 'lib/**/*.rb'
|
6
|
+
Exclude:
|
7
|
+
- 'bin/**/*'
|
8
|
+
- 'test/**/*'
|
9
|
+
|
10
|
+
Bundler:
|
11
|
+
Severity: error
|
12
|
+
Gemspec:
|
13
|
+
Severity: error
|
14
|
+
Style/StringLiterals:
|
15
|
+
Enabled: true
|
16
|
+
EnforcedStyle: double_quotes
|
17
|
+
|
18
|
+
Style/StringLiteralsInInterpolation:
|
19
|
+
Enabled: true
|
20
|
+
EnforcedStyle: double_quotes
|
21
|
+
|
22
|
+
Style/Documentation:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
Style/ClassVars:
|
26
|
+
Enabled: false
|
27
|
+
|
28
|
+
Layout/LineLength:
|
29
|
+
Max: 120
|
30
|
+
Metrics/ClassLength:
|
31
|
+
Max: 120
|
32
|
+
Metrics/MethodLength:
|
33
|
+
Max: 30
|
34
|
+
Metrics/AbcSize:
|
35
|
+
Enabled: false
|
36
|
+
Lint/MissingSuper:
|
37
|
+
Enabled: false
|
38
|
+
Lint/RescueException:
|
39
|
+
Enabled: false
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
|
2
|
+
# MQTT Subscriptions
|
3
|
+
|
4
|
+
## 1. **`trip_metrics` Subscription**
|
5
|
+
|
6
|
+
This subscription handles trip metrics and serializes the data related to trips, such as GPS location, battery status, and connection types.
|
7
|
+
|
8
|
+
### **Purpose:**
|
9
|
+
- To monitor the metrics of a trip in real-time, including the trip's ID, GPS data, battery level, location permissions, and notification permissions.
|
10
|
+
|
11
|
+
### **Payload Structure:**
|
12
|
+
```json
|
13
|
+
{
|
14
|
+
"trip_id": 123,
|
15
|
+
"metrics": {
|
16
|
+
"locPerms": 0,
|
17
|
+
"connt": "wf",
|
18
|
+
"batt": { "l": 100, "cs": "charging" },
|
19
|
+
"battPwOp": 0,
|
20
|
+
"pws": 0,
|
21
|
+
"notf": 1,
|
22
|
+
"gps": 1,
|
23
|
+
"nlog": 500,
|
24
|
+
"loc": {
|
25
|
+
"lat": 29.9585182,
|
26
|
+
"lon": 31.0423193,
|
27
|
+
"acc": 20,
|
28
|
+
"alt": 150.5,
|
29
|
+
"ts": 1729074275127 // unix timestamp
|
30
|
+
},
|
31
|
+
"ts": 1729074279737 // unix timestamp
|
32
|
+
}
|
33
|
+
}
|
34
|
+
```
|
35
|
+
|
36
|
+
### **Serialized Output:**
|
37
|
+
```ruby
|
38
|
+
{
|
39
|
+
trip_id: 123,
|
40
|
+
metrics: {
|
41
|
+
location_permission: "BACKGROUND_FINE",
|
42
|
+
connection_type: "wf",
|
43
|
+
battery: {
|
44
|
+
battery_level: 100,
|
45
|
+
charging_statuc: "charging",
|
46
|
+
opmization_status: 0,
|
47
|
+
power_saving_mode: 0
|
48
|
+
},
|
49
|
+
notification_permission: 1,
|
50
|
+
gps: 1,
|
51
|
+
location: {
|
52
|
+
latitude: 29.9585182,
|
53
|
+
longitude: 31.0423193,
|
54
|
+
accuracy: 20,
|
55
|
+
altitude: 150.5,
|
56
|
+
logged_at: 1729074275127 # unix timestamp
|
57
|
+
}
|
58
|
+
},
|
59
|
+
logged_at: 1729074275127, # unix timestamp
|
60
|
+
received_at: 1729074275127 # unix timestamp
|
61
|
+
}
|
62
|
+
```
|
63
|
+
|
64
|
+
---
|
65
|
+
|
66
|
+
### **Date Types:**
|
67
|
+
|
68
|
+
- To decode a unix timestamp use the following link [epoch_converter](https://www.epochconverter.com/)
|
69
|
+
|
70
|
+
---
|
71
|
+
|
72
|
+
### **Usage Example:**
|
73
|
+
```ruby
|
74
|
+
$client.subscribe('illa/trips/20/trip_metric/send/user/20') do |response|
|
75
|
+
puts "Received trip metrics: #{response}"
|
76
|
+
end
|
77
|
+
|
78
|
+
payload = {
|
79
|
+
"trip_id": 123,
|
80
|
+
"metrics": {
|
81
|
+
"locPerms": 0,
|
82
|
+
"connt": "wf",
|
83
|
+
"batt": { "l": 100, "cs": "charging" },
|
84
|
+
"battPwOp": 0,
|
85
|
+
"pws": 0,
|
86
|
+
"notf": 1,
|
87
|
+
"gps": 1,
|
88
|
+
"nlog": 500,
|
89
|
+
"loc": {
|
90
|
+
"lat": 29.9585182,
|
91
|
+
"lon": 31.0423193,
|
92
|
+
"acc": 20,
|
93
|
+
"alt": 150.5,
|
94
|
+
"ts": 1729074275127
|
95
|
+
},
|
96
|
+
"ts": 1729074279737
|
97
|
+
}
|
98
|
+
}
|
99
|
+
$client.publish('illa/trips/20/trip_metric/send/user/20', payload)
|
100
|
+
```
|
101
|
+
|
102
|
+
---
|
103
|
+
|
104
|
+
## 2. **`test_debug` Subscription**
|
105
|
+
|
106
|
+
The `test_debug` subscription is used for testing and debugging purposes, capturing payloads sent on specific MQTT topics.
|
107
|
+
|
108
|
+
### **Purpose:**
|
109
|
+
- To log and serialize MQTT messages for debugging purposes, capturing both the topic name and payload.
|
110
|
+
|
111
|
+
### **Payload Structure:**
|
112
|
+
```json
|
113
|
+
{
|
114
|
+
"topic_name": "test/topic",
|
115
|
+
"payload": { "message": "Hello, MQTT" }
|
116
|
+
}
|
117
|
+
```
|
118
|
+
|
119
|
+
### **Serialized Output:**
|
120
|
+
```ruby
|
121
|
+
{
|
122
|
+
topic_name: "test/topic",
|
123
|
+
payload: { message: "Hello, MQTT" },
|
124
|
+
received_at: 1729074275127 # unix timestamp
|
125
|
+
}
|
126
|
+
```
|
127
|
+
|
128
|
+
### **Usage Example:**
|
129
|
+
```ruby
|
130
|
+
$client.subscribe('test/#') do |response|
|
131
|
+
puts "Received debug message: #{response}"
|
132
|
+
end
|
133
|
+
|
134
|
+
$client.publish('test/topic', 'Hello, MQTT')
|
135
|
+
```
|
data/README.md
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
|
2
|
+
# Mqttopia
|
3
|
+
|
4
|
+
Mqttopia is a Ruby-based project designed to facilitate interactions with MQTT protocols. It provides a modular architecture for handling MQTT clients, subscriptions, and data serialization, making it easier to integrate MQTT into your applications.
|
5
|
+
|
6
|
+
---
|
7
|
+
|
8
|
+
## **Features**
|
9
|
+
|
10
|
+
- Configurable MQTT client with options for hosts, port, SSL, and authentication.
|
11
|
+
- Subscription handling for dynamic topics.
|
12
|
+
- Data serialization modules to standardize payloads.
|
13
|
+
- Custom Rake tasks for initializing configuration files.
|
14
|
+
|
15
|
+
---
|
16
|
+
|
17
|
+
## **Installation**
|
18
|
+
|
19
|
+
### Bundler
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
gem 'mqttopia', '~> 0.1.0'
|
23
|
+
```
|
24
|
+
|
25
|
+
### Manual
|
26
|
+
|
27
|
+
```sh
|
28
|
+
gem install mqttopia
|
29
|
+
```
|
30
|
+
|
31
|
+
---
|
32
|
+
|
33
|
+
## **Usage**
|
34
|
+
|
35
|
+
### Configuring Mqttopia
|
36
|
+
|
37
|
+
You can create or update the `mqttopia.rb` file using the included Rake task:
|
38
|
+
|
39
|
+
```bash
|
40
|
+
bundle exec rails generate mqttopia:install
|
41
|
+
```
|
42
|
+
|
43
|
+
The generated `mqttopia.rb` will contain:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
Mqttopia.configure do |config|
|
47
|
+
config.hosts = ["localhost"]
|
48
|
+
config.port = 1883
|
49
|
+
config.username = "user"
|
50
|
+
config.password = "xxxx"
|
51
|
+
config.ssl = true
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
### Example: Subscribing and Publishing Messages
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
client = Mqttopia::Client.instance
|
59
|
+
|
60
|
+
# Subscribe to a topic
|
61
|
+
client.subscribe('test/#') do |response|
|
62
|
+
puts "Received: #{response}"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Publish a message to a topic
|
66
|
+
client.publish('test/topic', 'Hello, MQTT')
|
67
|
+
```
|
68
|
+
|
69
|
+
### MQTT subscriptions
|
70
|
+
|
71
|
+
- [MQTT subscriptions](https://github.com/go-illa/mqttopia/blob/master/MQTT_SUBSCRIPTIONS.md)
|
72
|
+
|
73
|
+
---
|
74
|
+
|
75
|
+
## **Topic Name Structure**
|
76
|
+
|
77
|
+
- **send data** : `illa/{entity}/{entity_id}/{operation}/send/user/{user_id}`
|
78
|
+
- **ask data** : `illa/{entity}/{entity_id}/{operation}/ask/user/{user_id}`
|
79
|
+
- **operation** : `trip_metrics`, `test_debug`, ..etc.
|
80
|
+
- **entity**: `trips`
|
81
|
+
- `user/{user_id}` is optional
|
82
|
+
|
83
|
+
---
|
84
|
+
|
85
|
+
## **Rake Tasks**
|
86
|
+
|
87
|
+
### Available Tasks
|
88
|
+
|
89
|
+
- **Initialize Configuration File:**
|
90
|
+
|
91
|
+
Creates `mqttopia_initialize.rb` with default configurations.
|
92
|
+
|
93
|
+
```bash
|
94
|
+
bundle exec rake mqttopia:initialize
|
95
|
+
```
|
96
|
+
|
97
|
+
---
|
98
|
+
|
99
|
+
## **Project Structure**
|
100
|
+
|
101
|
+
```
|
102
|
+
mqttopia/
|
103
|
+
├── lib/
|
104
|
+
│ ├── mqttopia/ # Modules for mqttopia gem
|
105
|
+
│ | ├── helpers/ # Helper Modules
|
106
|
+
│ | ├── serializers/ # Modules for payload serialization
|
107
|
+
│ | ├── subscriptions/ # MQTT Topics's events and services
|
108
|
+
│ | └── topics/ # MQTT Topic constants [name, regex, service, serializer]
|
109
|
+
│ |── tasks/ # Rake tasks
|
110
|
+
│ ├── mqttopia.rb # Main entry point for the gem
|
111
|
+
│ ├── client.rb # MQTT client implementation
|
112
|
+
│ └── logger.rb # Logging setup
|
113
|
+
└── test/ # Minitest-based test suite
|
114
|
+
```
|
115
|
+
|
116
|
+
---
|
117
|
+
|
118
|
+
## **Contributing**
|
119
|
+
|
120
|
+
1. Fork the repository.
|
121
|
+
2. Create a feature branch: `git checkout -b feature-branch-name`
|
122
|
+
3. Commit your changes: `git commit -m "Add new feature"`
|
123
|
+
4. Push the branch: `git push origin feature-branch-name`
|
124
|
+
5. Open a Pull Request.
|
125
|
+
|
126
|
+
---
|
127
|
+
|
128
|
+
## **License**
|
129
|
+
|
130
|
+
This project is licensed under the MIT License. See the `LICENSE` file for more information.
|
131
|
+
|
132
|
+
---
|
133
|
+
|
134
|
+
## **Contact**
|
135
|
+
|
136
|
+
If you have any questions or need further assistance, feel free to open an issue or contact the maintainer.
|
137
|
+
|
138
|
+
---
|
139
|
+
|
140
|
+
## **Acknowledgements**
|
141
|
+
|
142
|
+
Special thanks to all contributors and users who have made this project possible.
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rake/testtask"
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << "test"
|
8
|
+
t.test_files = FileList['test/**/*_test.rb'] # Make sure all test files are loaded
|
9
|
+
# t.verbose = true # This will give more output during the test run
|
10
|
+
end
|
11
|
+
|
12
|
+
require "rubocop/rake_task"
|
13
|
+
|
14
|
+
RuboCop::RakeTask.new
|
15
|
+
|
16
|
+
task default: %i[test rubocop]
|
data/TEST_README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# TEST
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
```sh
|
6
|
+
gem install mqttopia
|
7
|
+
```
|
8
|
+
|
9
|
+
## Testing `test_mqttopia.rb`
|
10
|
+
|
11
|
+
1. create a new `test_mqttopia.rb` file
|
12
|
+
```sh
|
13
|
+
touch test_mqttopia.rb
|
14
|
+
```
|
15
|
+
|
16
|
+
2. file structure and testing scenarios
|
17
|
+
```ruby
|
18
|
+
# test_mqttopia.rb
|
19
|
+
|
20
|
+
# Require the gem's main file
|
21
|
+
require 'mqttopia'
|
22
|
+
|
23
|
+
# Initialize Mqttopia, using your mqtt server credentials
|
24
|
+
Mqttopia.configure do |config|
|
25
|
+
config.hosts = ["localhost"]
|
26
|
+
config.port = 1883
|
27
|
+
config.username = 'user'
|
28
|
+
config.password = 'xxxx'
|
29
|
+
config.ssl = true
|
30
|
+
config.debugging = true
|
31
|
+
end
|
32
|
+
|
33
|
+
begin
|
34
|
+
# Create a client instance (connect to mqtt server)
|
35
|
+
client = Mqttopia::Client.instance
|
36
|
+
|
37
|
+
# Subscribe to a topic and print received messages
|
38
|
+
client.subscribe('test/#') do |response|
|
39
|
+
puts "Received PROCESSED message: #{response}"
|
40
|
+
end
|
41
|
+
rescue StandardError => e
|
42
|
+
puts "MQTT CLIENT #{e}"
|
43
|
+
end
|
44
|
+
|
45
|
+
# Publish a message to the topic
|
46
|
+
client.publish('test/topic', 'Hello, MQTT')
|
47
|
+
|
48
|
+
puts 'Listening for new MQTT messages. Press Ctrl+C to exit.'
|
49
|
+
|
50
|
+
# Keep the script alive to listen indefinitely
|
51
|
+
sleep
|
52
|
+
```
|
53
|
+
|
54
|
+
3. Run the file
|
55
|
+
```sh
|
56
|
+
ruby test_mqttopia.rb
|
57
|
+
```
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/base"
|
4
|
+
|
5
|
+
module Mqttopia
|
6
|
+
module Generators
|
7
|
+
class InstallGenerator < Rails::Generators::Base
|
8
|
+
source_root File.expand_path("../templates", __dir__)
|
9
|
+
|
10
|
+
desc "Creates a Mqttopia initializer file for configuration."
|
11
|
+
|
12
|
+
# Method to generate the initializer
|
13
|
+
def copy_initializer
|
14
|
+
template "mqttopia_initializer.rb", "config/initializers/mqttopia.rb"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# config/initializers/mqttopia.rb
|
4
|
+
|
5
|
+
Mqttopia.configure do |config|
|
6
|
+
# Set the MQTT hosts
|
7
|
+
config.hosts = ["localhost"]
|
8
|
+
|
9
|
+
# Set the MQTT port
|
10
|
+
config.port = 1883
|
11
|
+
|
12
|
+
# Set the MQTT username
|
13
|
+
config.username = "user"
|
14
|
+
|
15
|
+
# Set the MQTT password
|
16
|
+
config.password = "xxxx"
|
17
|
+
|
18
|
+
# Set the MQTT ssl
|
19
|
+
config.ssl = true
|
20
|
+
|
21
|
+
# Set the MQTT debugging mode
|
22
|
+
# config.debugging = true
|
23
|
+
|
24
|
+
# Set the logger (defaults to STDOUT)
|
25
|
+
# config.logger = Logger.new(STDOUT)
|
26
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "mqtt"
|
4
|
+
require "json"
|
5
|
+
require "socket"
|
6
|
+
require_relative "subscriptions/redirect"
|
7
|
+
|
8
|
+
module Mqttopia
|
9
|
+
class Client
|
10
|
+
@instance = nil
|
11
|
+
attr_reader :mqtt_client, :debugging
|
12
|
+
|
13
|
+
def self.instance
|
14
|
+
@instance ||= new
|
15
|
+
end
|
16
|
+
|
17
|
+
private_class_method :new
|
18
|
+
|
19
|
+
def initialize(
|
20
|
+
username: Mqttopia.username,
|
21
|
+
password: Mqttopia.password,
|
22
|
+
port: Mqttopia.port,
|
23
|
+
ssl: Mqttopia.ssl
|
24
|
+
)
|
25
|
+
@mqtt_client = MQTT::Client.new(
|
26
|
+
port: port,
|
27
|
+
username: username,
|
28
|
+
password: password,
|
29
|
+
ssl: ssl,
|
30
|
+
keep_alive: 15,
|
31
|
+
ack_timeout: 5
|
32
|
+
)
|
33
|
+
@debugging = Mqttopia.debugging
|
34
|
+
rescue Exception => e
|
35
|
+
log_error("initialize", e)
|
36
|
+
end
|
37
|
+
|
38
|
+
def connect
|
39
|
+
host = active_host(Mqttopia.hosts)
|
40
|
+
raise ArgumentError, "No hosts available" if host.nil?
|
41
|
+
|
42
|
+
mqtt_client.host = host
|
43
|
+
mqtt_client.connect
|
44
|
+
rescue Exception => e
|
45
|
+
disconnect_and_log("connect", e)
|
46
|
+
end
|
47
|
+
|
48
|
+
def publish(topic, message = nil, qos = 0)
|
49
|
+
return unless ensure_connection
|
50
|
+
|
51
|
+
# publish(topic, payload = '', retain = false, qos = 0)
|
52
|
+
mqtt_client.publish(topic, message, false, qos)
|
53
|
+
log_debug("Sent message on topic #{topic}: #{message} with QOS #{qos}")
|
54
|
+
rescue Exception => e
|
55
|
+
disconnect_and_log("publish", e)
|
56
|
+
end
|
57
|
+
|
58
|
+
def subscribe(topic, qos = 0, &block)
|
59
|
+
return unless ensure_connection
|
60
|
+
|
61
|
+
mqtt_client.subscribe(topic => qos)
|
62
|
+
create_subscription_thread(qos, &block)
|
63
|
+
rescue Exception => e
|
64
|
+
disconnect_and_log("subscribe", e)
|
65
|
+
end
|
66
|
+
|
67
|
+
def disconnect
|
68
|
+
mqtt_client.disconnect if connected?
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def active_host(hosts = Mqttopia.hosts, port = Mqttopia.port, timeout = 10)
|
74
|
+
hosts.each do |host|
|
75
|
+
Socket.tcp(host, port, connect_timeout: timeout) do |sock|
|
76
|
+
sock.close
|
77
|
+
return host # Return the first reachable host
|
78
|
+
end
|
79
|
+
rescue SocketError, Errno::ECONNREFUSED, Errno::ETIMEDOUT, IOError
|
80
|
+
next # Ignore unreachable hosts and continue checking
|
81
|
+
end
|
82
|
+
nil # Return nil if no reachable host is found
|
83
|
+
end
|
84
|
+
|
85
|
+
def create_subscription_thread(qos, &block)
|
86
|
+
Thread.new do
|
87
|
+
mqtt_client.get do |topic, message|
|
88
|
+
log_debug("Received RAW message on topic #{topic}: #{message} with QOS #{qos}")
|
89
|
+
|
90
|
+
response = safe_mqtt_response(topic, message)
|
91
|
+
block.call(response) if response
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def safe_mqtt_response(topic_name, raw_payload)
|
97
|
+
Mqttopia::Subscriptions::Redirect.new(
|
98
|
+
topic_name: topic_name,
|
99
|
+
payload: parse_json(raw_payload)
|
100
|
+
).call
|
101
|
+
rescue Exception => e
|
102
|
+
log_error("safe_mqtt_response", e)
|
103
|
+
nil
|
104
|
+
end
|
105
|
+
|
106
|
+
def parse_json(payload)
|
107
|
+
JSON.parse(payload, symbolize_names: true)
|
108
|
+
rescue JSON::ParserError
|
109
|
+
payload
|
110
|
+
end
|
111
|
+
|
112
|
+
def ensure_connection
|
113
|
+
connected? || connect || connected?
|
114
|
+
end
|
115
|
+
|
116
|
+
def connected?
|
117
|
+
mqtt_client.connected?
|
118
|
+
end
|
119
|
+
|
120
|
+
def log_error(method, error)
|
121
|
+
Mqttopia::Logger.error("\nMqttopia::Client -> #{method}: #{error_details(error)}\n")
|
122
|
+
end
|
123
|
+
|
124
|
+
def log_debug(message)
|
125
|
+
Mqttopia::Logger.debug("\n#{message}\n") if debugging
|
126
|
+
end
|
127
|
+
|
128
|
+
def disconnect_and_log(method, error)
|
129
|
+
disconnect
|
130
|
+
log_error(method, error)
|
131
|
+
end
|
132
|
+
|
133
|
+
def error_details(error)
|
134
|
+
{
|
135
|
+
type: error.class.name&.gsub("Mqttopia::Subscriptions::Services::", ""),
|
136
|
+
message: error.message
|
137
|
+
}
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mqttopia
|
4
|
+
module Helpers
|
5
|
+
module DataExtractor
|
6
|
+
def extract_trip_id(topic_name)
|
7
|
+
return unless topic_name.include?("trips/")
|
8
|
+
|
9
|
+
match_data = topic_name.match(%r{trips/([^/]*)})
|
10
|
+
|
11
|
+
match_data && !match_data[1].empty? ? match_data[1] : nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def extract_user_id(topic_name)
|
15
|
+
return unless topic_name.include?("user/")
|
16
|
+
|
17
|
+
match_data = topic_name.match(%r{user/([^/]*)})
|
18
|
+
|
19
|
+
match_data && !match_data[1].empty? ? match_data[1] : nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/module/delegation" # Require ActiveSupport's delegation
|
4
|
+
|
5
|
+
module Mqttopia
|
6
|
+
class Logger
|
7
|
+
class << self
|
8
|
+
# Initialize the logger
|
9
|
+
def logger
|
10
|
+
@logger ||= Mqttopia.logger # Default to logging to STDOUT
|
11
|
+
end
|
12
|
+
|
13
|
+
# Allow users to set a custom logger (e.g., logging to a file)
|
14
|
+
attr_writer :logger
|
15
|
+
|
16
|
+
# Simple wrapper for logging debug messages
|
17
|
+
delegate :debug, to: :logger
|
18
|
+
|
19
|
+
# Wrapper for logging info messages
|
20
|
+
delegate :info, to: :logger
|
21
|
+
|
22
|
+
# Wrapper for logging warn messages
|
23
|
+
delegate :warn, to: :logger
|
24
|
+
|
25
|
+
# Wrapper for logging error messages
|
26
|
+
delegate :error, to: :logger
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mqttopia
|
4
|
+
module Serializers
|
5
|
+
module TestDebug
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def serialize(body)
|
9
|
+
{
|
10
|
+
topic_name: body[:topic_name],
|
11
|
+
payload: body[:payload],
|
12
|
+
received_at: DateTime.now.strftime("%Q")&.to_s
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mqttopia
|
4
|
+
module Serializers
|
5
|
+
module TripMetric
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def serialize(body)
|
9
|
+
{
|
10
|
+
trip_id: body[:trip_id],
|
11
|
+
metrics: body[:metrics] && metric_serialize(body[:metrics]),
|
12
|
+
logged_at: body[:metrics] && body[:metrics][:ts]&.to_s,
|
13
|
+
received_at: DateTime.now.strftime("%Q")&.to_s
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def metric_serialize(metric)
|
18
|
+
{
|
19
|
+
location_permission: location_permission_mapper(metric[:locPerms]),
|
20
|
+
connection_type: metric[:connt],
|
21
|
+
battery: {
|
22
|
+
battery_level: metric[:batt] && metric[:batt][:l],
|
23
|
+
charging_statuc: metric[:batt] && metric[:batt][:cs],
|
24
|
+
opmization_status: metric[:battPwOp],
|
25
|
+
power_saving_mode: metric[:pws]
|
26
|
+
},
|
27
|
+
notification_permission: metric[:notf],
|
28
|
+
gps: metric[:gps],
|
29
|
+
number_of_trip_logs: metric[:nlog],
|
30
|
+
location: metric[:loc] && {
|
31
|
+
latitude: metric[:loc][:lat],
|
32
|
+
longitude: metric[:loc][:lon],
|
33
|
+
accuracy: metric[:loc][:acc],
|
34
|
+
altitude: metric[:loc][:alt],
|
35
|
+
logged_at: metric[:loc][:ts]&.to_s
|
36
|
+
}
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def location_permission_mapper(location_permission)
|
41
|
+
case location_permission
|
42
|
+
when 0
|
43
|
+
"BACKGROUND_FINE"
|
44
|
+
when -1
|
45
|
+
"BACKGROUND_COARSE"
|
46
|
+
when -2
|
47
|
+
"FOREGROUND_FINE"
|
48
|
+
when -3
|
49
|
+
"FOREGROUND_COARSE"
|
50
|
+
when -4
|
51
|
+
"DISABLED"
|
52
|
+
else
|
53
|
+
"UNKNOWN"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "services/trip_metrics"
|
4
|
+
require_relative "services/test_debug"
|
5
|
+
require_relative "../topics/services"
|
6
|
+
|
7
|
+
module Mqttopia
|
8
|
+
module Subscriptions
|
9
|
+
class Redirect
|
10
|
+
attr_reader :topic_name, :payload, :debugging
|
11
|
+
|
12
|
+
def initialize(topic_name:, payload:)
|
13
|
+
@topic_name = topic_name
|
14
|
+
@payload = payload
|
15
|
+
@debugging = Mqttopia.debugging
|
16
|
+
end
|
17
|
+
|
18
|
+
def call
|
19
|
+
Mqttopia::Topics::Services::KEYS.each_value do |value|
|
20
|
+
next unless topic_name.match(value[:regex])
|
21
|
+
|
22
|
+
return value[:service].safe_constantize.call(
|
23
|
+
topic_name,
|
24
|
+
payload,
|
25
|
+
{ serializer: value[:serializer] }
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
Mqttopia::Logger.warn "No matching topic found for #{topic_name}" if debugging
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mqttopia
|
4
|
+
module Subscriptions
|
5
|
+
module Services
|
6
|
+
class Base
|
7
|
+
include ActiveModel::Validations
|
8
|
+
extend Mqttopia::Helpers::DataExtractor
|
9
|
+
|
10
|
+
def self.call(topic, payload, _options = {})
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_model"
|
4
|
+
require_relative "../../serializers/test_debug"
|
5
|
+
require_relative "./base"
|
6
|
+
|
7
|
+
module Mqttopia
|
8
|
+
module Subscriptions
|
9
|
+
module Services
|
10
|
+
class TestDebug < Mqttopia::Subscriptions::Services::Base
|
11
|
+
class TestDebugInvalidError < ArgumentError
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :topic_name, :payload, :options
|
15
|
+
|
16
|
+
validates :topic_name, presence: true
|
17
|
+
validates :payload, presence: true
|
18
|
+
|
19
|
+
def initialize(topic_name:, payload:, options: {})
|
20
|
+
@topic_name = topic_name
|
21
|
+
@payload = payload
|
22
|
+
@options = options
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.call(topic, payload, options = {})
|
26
|
+
new(topic_name: topic, payload: payload, options: options).process
|
27
|
+
end
|
28
|
+
|
29
|
+
def process
|
30
|
+
raise TestDebugInvalidError, errors.full_messages.to_sentence unless valid?
|
31
|
+
|
32
|
+
Mqttopia::Serializers::TestDebug.serialize({
|
33
|
+
topic_name: topic_name,
|
34
|
+
payload: payload
|
35
|
+
})
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_model"
|
4
|
+
require_relative "../../serializers/trip_metric"
|
5
|
+
require_relative "../../helpers/data_extractor"
|
6
|
+
require_relative "./base"
|
7
|
+
|
8
|
+
module Mqttopia
|
9
|
+
module Subscriptions
|
10
|
+
module Services
|
11
|
+
class TripMetrics < Mqttopia::Subscriptions::Services::Base
|
12
|
+
class TripMetricsInvalidError < ArgumentError
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :trip_id, :metrics, :options, :user_id
|
16
|
+
|
17
|
+
validates :trip_id, presence: true, numericality: { only_integer: true, greater_than: 0 }
|
18
|
+
validates :metrics, presence: true
|
19
|
+
|
20
|
+
def initialize(trip_id:, metrics:, options: {})
|
21
|
+
@trip_id = trip_id
|
22
|
+
@metrics = metrics
|
23
|
+
@options = options
|
24
|
+
@user_id = options[:user_id]
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.call(topic, payload, options = {})
|
28
|
+
trip_id = topic.include?("trips/") && topic.match(%r{trips/[^/]+}) && extract_trip_id(topic)
|
29
|
+
options[:user_id] = topic.include?("user/") && topic.match(%r{user/[^/]+}) && extract_user_id(topic)
|
30
|
+
|
31
|
+
new(trip_id: trip_id, metrics: payload, options: options).process
|
32
|
+
end
|
33
|
+
|
34
|
+
def process
|
35
|
+
raise TripMetricsInvalidError, errors.full_messages.to_sentence unless valid?
|
36
|
+
|
37
|
+
Mqttopia::Serializers::TripMetric.serialize({
|
38
|
+
trip_id: trip_id,
|
39
|
+
metrics: metrics
|
40
|
+
})
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mqttopia
|
4
|
+
module Topics
|
5
|
+
class Services
|
6
|
+
KEYS = {
|
7
|
+
trip_metric: {
|
8
|
+
topic_name: "illa/trips/:trip_id/trip_metric/send/user/:user_id",
|
9
|
+
service: "Mqttopia::Subscriptions::Services::TripMetrics",
|
10
|
+
serializer: "Mqttopia::Serializers::TripMetric",
|
11
|
+
regex: %r{\Ailla/trips/(?<trip_id>\d+)/trip_metric/send(?:/user/(?<user_id>\d+))?\z}
|
12
|
+
},
|
13
|
+
test_debug: {
|
14
|
+
topic_name: "test",
|
15
|
+
service: "Mqttopia::Subscriptions::Services::TestDebug",
|
16
|
+
serializer: "Mqttopia::Serializers::TripMetric",
|
17
|
+
regex: %r{test/}
|
18
|
+
}
|
19
|
+
}.freeze
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/mqttopia.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
|
5
|
+
require_relative "mqttopia/version"
|
6
|
+
require_relative "mqttopia/client"
|
7
|
+
require_relative "mqttopia/logger"
|
8
|
+
|
9
|
+
# Load rake tasks
|
10
|
+
Dir[File.expand_path("tasks/**/*.rake", __dir__)].each { |task| load task }
|
11
|
+
|
12
|
+
# Base module for Mqttopia Gem
|
13
|
+
module Mqttopia
|
14
|
+
class Error < StandardError; end
|
15
|
+
|
16
|
+
mattr_accessor :hosts, :port, :username, :password, :ssl, :logger, :debugging
|
17
|
+
|
18
|
+
@@port = 1883
|
19
|
+
@@ssl = true
|
20
|
+
@@logger = ::Logger.new($stdout)
|
21
|
+
@@debugging = false
|
22
|
+
|
23
|
+
def self.configure
|
24
|
+
yield self
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# lib/tasks/initialize.rake
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
namespace :mqttopia do
|
5
|
+
desc "Create mqttopia_initialize.rb with default configuration"
|
6
|
+
task :initialize do
|
7
|
+
file_name = 'mqttopia_initialize.rb'
|
8
|
+
content = <<~RUBY
|
9
|
+
Mqttopia.configure do |config|
|
10
|
+
# Set the MQTT host
|
11
|
+
config.hosts = ["localhost"]
|
12
|
+
|
13
|
+
# Set the MQTT port
|
14
|
+
config.port = 1883
|
15
|
+
|
16
|
+
# Set the MQTT username
|
17
|
+
config.username = "user"
|
18
|
+
|
19
|
+
# Set the MQTT password
|
20
|
+
config.password = "xxxx"
|
21
|
+
|
22
|
+
# Set the MQTT ssl
|
23
|
+
config.ssl = true
|
24
|
+
|
25
|
+
# Set the MQTT debugging mode
|
26
|
+
# config.debugging = true
|
27
|
+
|
28
|
+
# Set the logger (defaults to STDOUT)
|
29
|
+
# config.logger = Logger.new(STDOUT)
|
30
|
+
end
|
31
|
+
|
32
|
+
# $client = Mqttopia::Client.instance
|
33
|
+
# $client.subscribe('test/#') { |res| puts res }
|
34
|
+
# $client.publish('test/topic', 'Hello, MQTT')
|
35
|
+
RUBY
|
36
|
+
|
37
|
+
if File.exist?(file_name)
|
38
|
+
puts "Skipping: #{file_name} already exists"
|
39
|
+
else
|
40
|
+
File.write(file_name, content)
|
41
|
+
puts "Created: #{file_name}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/mqttopia.gemspec
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/mqttopia/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "mqttopia"
|
7
|
+
spec.version = Mqttopia::VERSION
|
8
|
+
spec.authors = ["Illa Tech"]
|
9
|
+
spec.email = ["tech@illa.com.eg"]
|
10
|
+
|
11
|
+
spec.summary = "Mqttopia"
|
12
|
+
spec.description = "Mqttopia description"
|
13
|
+
spec.homepage = "https://github.com/go-illa"
|
14
|
+
spec.required_ruby_version = ">= 2.7.0"
|
15
|
+
|
16
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
17
|
+
spec.metadata["source_code_uri"] = "https://github.com/go-illa/mqttopia"
|
18
|
+
spec.metadata["changelog_uri"] = "https://github.com/go-illa/mqttopia"
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
+
spec.files = Dir.chdir(__dir__) do
|
23
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
24
|
+
(File.expand_path(f) == __FILE__) ||
|
25
|
+
f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
spec.bindir = "exe"
|
29
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
30
|
+
spec.require_paths = ["lib"]
|
31
|
+
|
32
|
+
# Uncomment to register a new dependency of your gem
|
33
|
+
spec.add_dependency "activemodel", ">= 4.1"
|
34
|
+
spec.add_dependency "json", ">= 1.6"
|
35
|
+
spec.add_dependency "logger", ">= 1.4"
|
36
|
+
spec.add_dependency "mqtt", ">= 0.6"
|
37
|
+
spec.add_dependency "railties", ">= 4.2"
|
38
|
+
spec.add_dependency "rake", ">= 11.0"
|
39
|
+
|
40
|
+
spec.add_development_dependency "brakeman", "~> 6.0"
|
41
|
+
spec.add_development_dependency "fasterer", "~> 0.10"
|
42
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
43
|
+
spec.add_development_dependency "mocha", "~> 2.0"
|
44
|
+
spec.add_development_dependency "yard", "~> 0.9"
|
45
|
+
|
46
|
+
spec.post_install_message = '
|
47
|
+
[MQTTOPIA] Please make sure to run `rails generate mqttopia:install`
|
48
|
+
'
|
49
|
+
end
|
data/sig/mqttopia.rbs
ADDED
metadata
ADDED
@@ -0,0 +1,223 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mqttopia
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.9
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Illa Tech
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-10-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activemodel
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: logger
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.4'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: mqtt
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.6'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.6'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: railties
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '4.2'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '4.2'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '11.0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '11.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: brakeman
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '6.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '6.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: fasterer
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.10'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.10'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: minitest
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '5.0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '5.0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: mocha
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '2.0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '2.0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: yard
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0.9'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0.9'
|
167
|
+
description: Mqttopia description
|
168
|
+
email:
|
169
|
+
- tech@illa.com.eg
|
170
|
+
executables: []
|
171
|
+
extensions: []
|
172
|
+
extra_rdoc_files: []
|
173
|
+
files:
|
174
|
+
- ".rubocop.yml"
|
175
|
+
- CHANGELOG.md
|
176
|
+
- MQTT_SUBSCRIPTIONS.md
|
177
|
+
- README.md
|
178
|
+
- Rakefile
|
179
|
+
- TEST_README.md
|
180
|
+
- lib/generators/mqttopia/install_generator.rb
|
181
|
+
- lib/generators/templates/mqttopia_initializer.rb
|
182
|
+
- lib/mqttopia.rb
|
183
|
+
- lib/mqttopia/client.rb
|
184
|
+
- lib/mqttopia/helpers/data_extractor.rb
|
185
|
+
- lib/mqttopia/logger.rb
|
186
|
+
- lib/mqttopia/serializers/test_debug.rb
|
187
|
+
- lib/mqttopia/serializers/trip_metric.rb
|
188
|
+
- lib/mqttopia/subscriptions/redirect.rb
|
189
|
+
- lib/mqttopia/subscriptions/services/base.rb
|
190
|
+
- lib/mqttopia/subscriptions/services/test_debug.rb
|
191
|
+
- lib/mqttopia/subscriptions/services/trip_metrics.rb
|
192
|
+
- lib/mqttopia/topics/services.rb
|
193
|
+
- lib/mqttopia/version.rb
|
194
|
+
- lib/tasks/initialize.rake
|
195
|
+
- mqttopia.gemspec
|
196
|
+
- sig/mqttopia.rbs
|
197
|
+
homepage: https://github.com/go-illa
|
198
|
+
licenses: []
|
199
|
+
metadata:
|
200
|
+
homepage_uri: https://github.com/go-illa
|
201
|
+
source_code_uri: https://github.com/go-illa/mqttopia
|
202
|
+
changelog_uri: https://github.com/go-illa/mqttopia
|
203
|
+
post_install_message: "\n [MQTTOPIA] Please make sure to run `rails generate
|
204
|
+
mqttopia:install`\n "
|
205
|
+
rdoc_options: []
|
206
|
+
require_paths:
|
207
|
+
- lib
|
208
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
209
|
+
requirements:
|
210
|
+
- - ">="
|
211
|
+
- !ruby/object:Gem::Version
|
212
|
+
version: 2.7.0
|
213
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
214
|
+
requirements:
|
215
|
+
- - ">="
|
216
|
+
- !ruby/object:Gem::Version
|
217
|
+
version: '0'
|
218
|
+
requirements: []
|
219
|
+
rubygems_version: 3.5.19
|
220
|
+
signing_key:
|
221
|
+
specification_version: 4
|
222
|
+
summary: Mqttopia
|
223
|
+
test_files: []
|