fluent-plugin-everysense 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2476a0c5fa9ab1ef30dea01672bdf9eac541c5b1
4
- data.tar.gz: b3677753924f3ac0b5436971baa84ab0e642432e
3
+ metadata.gz: c77e04a5016b57e7dc362cfcad0fbb920cce6807
4
+ data.tar.gz: f98ffde7cf600e3653b1ede752fa854623684b55
5
5
  SHA512:
6
- metadata.gz: 52a8b2adf242993748e7e0fa6a2fce7e02fdcd9c00598afcd6ce2473614a22866a924aecdd764891d4f23deb2a5b5252eeaf0f28d8649fe5fd9cb8f113baacc0
7
- data.tar.gz: faeee261bf9a0518f3fd455e2e9a2d8409f91e6b8f409e719d9d9714d41ed37d02b580f3267a83e7d6e69f7d146535b070fef52be45848d8e858b12319ae1f9d
6
+ metadata.gz: 80d75ae58e2500dab081e641606738e0f966ee0b2fc4a0b65525a96c27ce2db2656b0b8208d5308fc08c9653c7c381f966a2f436f845840e65ef697a13d99c66
7
+ data.tar.gz: 3028ecae8d2185213aebffebb2d628deda3bc61f2a5dadef59c02181859b9109d10351980185d0478e0436ce7dd510e9cfacec4851681cb7b1ce635e50f1a565
data/README.md CHANGED
@@ -31,8 +31,8 @@ Input Plugin can be used via source directive in the configuration.
31
31
  tag tag_name
32
32
  login_name your_login_name
33
33
  password your_password
34
- device_id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx
35
- polling_interval 15
34
+ recipe_id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx
35
+ polling_interval 30
36
36
  </source>
37
37
  ```
38
38
 
@@ -44,30 +44,64 @@ Input Plugin can be used via source directive in the configuration.
44
44
  - **recipe_id** (device_id or recipe_id is required): the target recipe id to obtain input data
45
45
  - **polling_interval**: interval to poll EverySense JSON over HTTP API
46
46
 
47
+ Since each device may have multiple sensors, time field is generated when Input Plugin received data from EverySense. It can be used only for inside the fluentd network because the real timestamps for the sensors are recorded inside JSON data and not synchronized to the time field. An example record format of the Input Plugin is as follows:
48
+
49
+ ```
50
+ {"json":
51
+ [
52
+ {"data": {
53
+ "at": "2016-05-15 12:14:30 +0900",
54
+ "unit":"degree Celsius",
55
+ "value":23
56
+ },
57
+ "sensor_name":"collection_data_1"
58
+ },
59
+ {"data": {
60
+ "at":"2016-05-15 12:14:30 +0900",
61
+ "unit":"%RH",
62
+ "value":30
63
+ },
64
+ "sensor_name":"collection_data_2"}
65
+ ]
66
+ }
67
+ ```
68
+
69
+ While fluentd record must be a map (Hash), the output of EverySense becomes an array. So, a key ("json") is added to make it as a map.
47
70
 
48
71
  ### Output Plugin (Fluent::EverySenseOutput)
49
72
 
50
- Output Plugin can be used via match directive.
73
+ Output Plugin can be used via match directive. Output Plugin assumes the input format as described above.
51
74
 
52
75
  ```
53
76
  <match tag_name>
54
77
  @type everysense
55
78
  login_name your_login_name
56
79
  password your_password
57
- format json
58
80
  device_id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx
81
+ flush_interval 10
82
+ aggr_type none
83
+ <sensor>
84
+ input_name collection_data_1
85
+ output_name FESTIVAL_Test1_Sensor
86
+ type_of_value Integer
87
+ </sensor>
88
+ <sensor>
89
+ input_name collection_data_2
90
+ output_name FESTIVAL_Test1_Sensor2
91
+ type_of_value Integer
92
+ </sensor>
59
93
  </match>
60
94
  ```
61
95
 
62
- - **format** (required): type of formatter can be specified to parse input data
63
96
  - **login_name** (required): login_name to login https://service.every-sense.com/
64
97
  - **password** (required): password for the login_name
65
- - **device_id** (required): the target device id to submit sensor data
66
-
67
-
68
- ## TODO
69
-
70
- Recipe related function is not implemented yet.
98
+ - **device_id** (required): The target device id to submit sensor data
99
+ - **flush_interval**: Upload interval (default: 30)
100
+ - **aggr_type**: Buffered sensor data can be aggregated with specified statistic method. Currently avg (average) and none (without aggregation) can be specified (default: none).
101
+ - **sensor** (required): Output sensor names must be specified by sensor directive. Sensor data with the specified input_name will be uploaded to EverySense server with the output_name. If the input device data includes multiple sensor data, multiple directives can be specified. If sensor_name of input sensor data is not specified in the configuration, that sensor data will be skipped. If the sensor_names of input data are nil, sensor data will be uploaded with the number of sensor directives with the specified output_name.
102
+ - **input_name**: sensor_name of the input sensor data.
103
+ - **output_name**: sensor_name of the output sensor data.
104
+ - **type_of_value**: type of value (default: Integer)
71
105
 
72
106
 
73
107
  ## Contributing
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "fluent-plugin-everysense"
7
- spec.version = "0.0.4"
7
+ spec.version = "0.0.5"
8
8
  spec.authors = ["Toyokazu Akiyama"]
9
9
  spec.email = ["toyokazu@gmail.com"]
10
10
 
@@ -12,12 +12,9 @@ module Fluent
12
12
  base.desc 'EverySense API URI'
13
13
  base.config_param :url, :string, :default => 'https://api.every-sense.com:8001/'
14
14
  base.desc 'login_name for EverySense API'
15
- base.config_param :login_name, :string, :default => nil # TODO: mandatory option
15
+ base.config_param :login_name, :string
16
16
  base.desc 'password for EverySense API'
17
- base.config_param :password, :string, :default => nil # TODO: mandatory option
18
- base.config_param :device_id, :string, :default => nil
19
- base.config_param :recipe_id, :string, :default => nil
20
- base.config_param :format, :string, :default => 'json'
17
+ base.config_param :password, :string
21
18
  base.config_param :limit, :integer, :default => 1000
22
19
  #base.config_param :keep_alive, :integer, :default => 2
23
20
  base.config_param :from, :string, :default => Time.now.iso8601
@@ -26,7 +23,7 @@ module Fluent
26
23
  end
27
24
 
28
25
  def start_proxy
29
- $log.debug "start everysense proxy #{@uri}"
26
+ $log.debug "start everysense proxy #{@url}"
30
27
 
31
28
  @uri = URI.parse(@url)
32
29
  @https = Net::HTTP.new(@uri.host, @uri.port)
@@ -88,6 +85,7 @@ module Fluent
88
85
  end
89
86
 
90
87
  def put_message(message)
88
+ $log.debug "put_message: #{message}"
91
89
  put_message_res = @https.request(put_message_request(message))
92
90
  error_handler(put_message_res, "put_message: '#{message}' failed.")
93
91
  end
@@ -123,7 +121,7 @@ module Fluent
123
121
  get_messages_req.query = URI.encode_www_form(get_messages_params)
124
122
  $log.debug "#{@uri + target_path}?#{URI.encode_www_form(get_messages_params)}"
125
123
  # currently time window is automatically updated
126
- @from = (Time.now + 1).iso8601
124
+ @from = Time.now.iso8601
127
125
  get_messages_req
128
126
  end
129
127
 
@@ -134,6 +132,7 @@ module Fluent
134
132
  end
135
133
  get_messages_res = @https.get(get_messages_request)
136
134
  return nil if !error_handler(get_messages_res,"get_messages failed.")
135
+ $log.debug "get_message: #{get_messages_res.body}"
137
136
  get_messages_res.body
138
137
  end
139
138
  end
@@ -5,8 +5,38 @@ module Fluent
5
5
 
6
6
  Plugin.register_input('everysense', self)
7
7
 
8
+ config_param :format, :string, :default => 'json'
9
+
8
10
  # currently EverySenseParser is only used by EverySense Plugin
9
11
  # Parser is implemented internally.
12
+ # received message format of EverySense is as follows
13
+ #
14
+ # [
15
+ # [
16
+ # {
17
+ # "farm_uuid": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
18
+ # "sensor_name": "collection_data_1",
19
+ # "data_class_name": "AirTemperature",
20
+ # "data": {
21
+ # "at": "2016-05-12 21:38:52 UTC",
22
+ # "memo": null,
23
+ # "value": 23,
24
+ # "unit": "degree Celsius"
25
+ # }
26
+ # },
27
+ # {
28
+ # "farm_uuid": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
29
+ # "sensor_name": "collection_data_2",
30
+ # "data_class_name": "AirHygrometer",
31
+ # "data": {
32
+ # "at": "2016-05-12 21:38:52 UTC",
33
+ # "memo": null,
34
+ # "value": 30,
35
+ # "unit": "%RH"
36
+ # }
37
+ # }
38
+ # ]
39
+ # ]
10
40
  class EverySenseParser
11
41
  def initialize(format, parser)
12
42
  case format
@@ -25,9 +55,9 @@ module Fluent
25
55
  # each message is re-formatted to JSON. After that it is re-parsed
26
56
  # by fluent JSON parser which supports time_format etc. options...
27
57
  def parse(messages)
28
- $log.debug messages
58
+ #$log.debug messages
29
59
  JSON.parse(messages).map do |message|
30
- $log.debug message
60
+ #$log.debug message
31
61
  @parser.parse(message.to_json) do |time, record|
32
62
  yield(time, record)
33
63
  end
@@ -39,10 +69,10 @@ module Fluent
39
69
  config_param :tag, :string, :default => nil # TODO: mandatory option
40
70
  desc 'Polling interval to get message from EverySense API'
41
71
  config_param :polling_interval, :integer, :default => 60
42
- desc 'Adding timestamp to the message for monitoring performance'
43
- config_param :recv_time, :bool, :default => false
44
- desc 'Attribute name of the timestamp for receiving time'
45
- config_param :recv_time_key, :string, :default => "recv_time"
72
+ desc 'Device ID'
73
+ config_param :device_id, :string, :default => nil
74
+ desc 'Recipe ID'
75
+ config_param :recipe_id, :string, :default => nil
46
76
 
47
77
  # Define `router` method of v0.12 to support v0.10 or earlier
48
78
  unless method_defined?(:router)
@@ -68,7 +98,6 @@ module Fluent
68
98
  while (true)
69
99
  begin
70
100
  messages = get_messages
71
- $log.debug "get_messages: #{messages}"
72
101
  emit(messages) if !(messages.nil? || messages.empty?)
73
102
  sleep @polling_interval
74
103
  rescue Exception => e
@@ -81,30 +110,21 @@ module Fluent
81
110
  end
82
111
  end
83
112
 
84
- def add_recv_time(record)
85
- if @recv_time
86
- # recv_time is recorded in ms
87
- record.merge({@recv_time_key => Time.now.instance_eval { self.to_i * 1000 + (usec/1000) }})
88
- else
89
- record
90
- end
91
- end
92
-
93
113
  def parse(messages)
94
114
  @everysense_parser.parse(messages) do |time, record|
95
115
  if time.nil?
96
116
  $log.debug "Since time_key field is nil, Fluent::Engine.now is used."
97
117
  time = Fluent::Engine.now
98
118
  end
99
- $log.debug "#{time}, #{add_recv_time(record)}"
100
- {time: time, record: add_recv_time(record)}
119
+ #$log.debug "#{time}, #{record}"
120
+ {time: time, record: record}
101
121
  end
102
122
  end
103
123
 
104
124
  def emit(messages)
105
125
  begin
106
126
  parse(messages).each do |msg|
107
- router.emit(@tag, msg[:time], msg[:record])
127
+ router.emit(@tag, msg[:time], {json: msg[:record]})
108
128
  end
109
129
  rescue Exception => e
110
130
  $log.error :error => e.to_s
@@ -1,4 +1,7 @@
1
1
  module Fluent
2
+ # EverySenseOutput
3
+ # output data to EverySense server
4
+ # this module assumes the input format follows everysense output specification
2
5
  class EverySenseOutput < BufferedOutput
3
6
  require 'fluent/plugin/everysense_proxy'
4
7
  include EverySenseProxy
@@ -7,8 +10,38 @@ module Fluent
7
10
 
8
11
  # config_param defines a parameter. You can refer a parameter via @path instance variable
9
12
  # Without :default, a parameter is required.
10
- #desc 'Flush interval to put message to EverySense API'
11
- #config_param :flush_interval, :integer, :default => 15
13
+ desc 'Device ID'
14
+ config_param :device_id, :string
15
+ desc 'Flush interval to put message to EverySense API'
16
+ config_param :flush_interval, :integer, :default => 30
17
+ # aggr_type: "none", "avg", "max", "min"
18
+ desc 'Aggregation type'
19
+ config_param :aggr_type, :string, :default => "none"
20
+ # <sensor> is mandatory option
21
+ # an example configuraton is shown below
22
+ #
23
+ # <sensor>
24
+ # input_name collection_data_1
25
+ # output_name FESTIVAL_Test1_Sensor
26
+ # type_of_value Integer
27
+ # </sensor>
28
+ # <sensor>
29
+ # input_name collection_data_1
30
+ # output_name FESTIVAL_Test1_Sensor2
31
+ # type_of_value Integer
32
+ # </sensor>
33
+ config_section :sensor, required: true, multi: true do
34
+ desc 'Input sensor name'
35
+ config_param :input_name, :string, :default => nil
36
+ desc 'Output sensor name'
37
+ config_param :output_name, :string
38
+ # type_of_value: "Integer", "Float", "String", etc. The same as Ruby Class name.
39
+ desc 'Type of value'
40
+ config_param :type_of_value, :string, :default => "Integer"
41
+ # unit: "degree Celsius", "%RH", ...
42
+ #desc 'unit'
43
+ #config_param :unit, :string, :default => nil
44
+ end
12
45
 
13
46
  # This method is called before starting.
14
47
  # 'conf' is a Hash that includes configuration parameters.
@@ -16,11 +49,23 @@ module Fluent
16
49
  def configure(conf)
17
50
  super
18
51
  configure_formatter(conf)
52
+ #@sensor.each do |s|
53
+ # $log.debug s.to_h.inspect
54
+ #end
55
+ @sensor_hash = {}
56
+ @sensor.each do |sensor|
57
+ if sensor.to_h[:input_name].nil?
58
+ @sensor_hash[sensor.to_h[:output_name]] = sensor.to_h
59
+ else
60
+ @sensor_hash[sensor.to_h[:input_name]] = sensor.to_h
61
+ end
62
+ end
63
+ $log.debug @sensor_hash.inspect
19
64
  end
20
65
 
21
66
  def configure_formatter(conf)
22
- @formatter = Plugin.new_formatter(@format)
23
- @formatter.configure(conf)
67
+ #@formatter = Plugin.new_formatter(@format)
68
+ #@formatter.configure(conf)
24
69
  end
25
70
 
26
71
  # This method is called when starting.
@@ -30,25 +75,123 @@ module Fluent
30
75
  start_proxy
31
76
  end
32
77
 
33
- def add_send_time(record)
34
- if @send_time
35
- # send_time is recorded in ms
36
- record.merge({@send_time_key => Time.now.instance_eval { self.to_i * 1000 + (usec/1000) }})
78
+ def format(tag, time, record)
79
+ $log.debug "tag: #{tag}, time: #{time}, record: #{record}"
80
+ [tag, time, record].to_msgpack
81
+ end
82
+
83
+ def force_type(value)
84
+ case @type_of_value
85
+ when "Integer"
86
+ return value.to_i
87
+ when "Float"
88
+ return value.to_f
89
+ when "String"
90
+ return value.to_s
37
91
  else
38
- record
92
+ return value.to_i
39
93
  end
40
94
  end
41
95
 
42
- def format(tag, time, record)
43
- [tag, time, record].to_msgpack
96
+ # output message format of EverySense is as follows
97
+ #
98
+ # [
99
+ # {
100
+ # "data": {
101
+ # "at":"2016-04-14 17:15:00 +0900",
102
+ # "unit":"degree Celsius",
103
+ # "value":23
104
+ # },
105
+ # "sensor_name":"FESTIVAL_Test1_Sensor"
106
+ # },
107
+ # {
108
+ # "data": {
109
+ # "at":"2016-04-14 17:15:00 +0900",
110
+ # "unit":"%RH",
111
+ # "value":30
112
+ # },
113
+ # "sensor_name":"FESTIVAL_Test1_Sensor2"
114
+ # }
115
+ # ]
116
+ def transform_sensor_data(sensor_data, output_name) # modify sensor_name
117
+ {
118
+ data: {
119
+ at: Time.parse(sensor_data["data"]["at"]),
120
+ unit: sensor_data["data"]["unit"],
121
+ value: force_type(sensor_data["data"]["value"])
122
+ },
123
+ sensor_name: output_name
124
+ }
125
+ end
126
+
127
+ def get_output_name_by_name(input_name)
128
+ @sensor_hash[input_name][:output_name]
129
+ end
130
+
131
+ def get_output_name_by_index(index)
132
+ @sensor_hash[@sensor_hash.keys[index]][:output_name]
133
+ end
134
+
135
+ def transform_device_data(device_data)
136
+ if device_data[0]["sensor_name"].nil?
137
+ # if first input data does not include sensor_name,
138
+ # output_names are used in the specified order.
139
+ return device_data.map.with_index do |sensor_data, i|
140
+ if !get_output_name_by_index(i).nil?
141
+ transform_sensor_data(sensor_data, get_output_name_by_index(i))
142
+ end
143
+ end.compact
144
+ end
145
+ device_data.map do |sensor_data|
146
+ #$log.debug sensor_data["sensor_name"]
147
+ if @sensor_hash.keys.include?(sensor_data["sensor_name"])
148
+ transform_sensor_data(sensor_data, get_output_name_by_name(sensor_data["sensor_name"]))
149
+ end
150
+ end.compact
151
+ end
152
+
153
+ def avg(chunk)
154
+ device_data_list = []
155
+ chunk.msgpack_each do |tag, time, device_data|
156
+ device_data_list << transform_device_data(device_data)
157
+ end
158
+ avg_device_data = device_data_list[0]
159
+ device_data_list[1..-1].each do |device_data|
160
+ avg_device_data.each_with_index do |avg_sensor_data, i|
161
+ avg_sensor_data[:data][:at].to_i += device_data[i][:data][:at].to_i
162
+ avg_sensor_data[:data][:value] += device_data[i][:data][:value]
163
+ end
164
+ end
165
+ avg_device_data.each_with_index do |avg_sensor_data, i|
166
+ # average time
167
+ avg_sensor_data[:data][:at] = Time.at((avg_sensor_data[:data][:at] / device_data_list.size).to_i)
168
+ # average value
169
+ avg_sensor_data[:data][:value] = force_type(avg_sensor_data[:data][:value] / device_data_list.size)
170
+ end
171
+ $log.debug avg_device_data.to_json
172
+ put_message(avg_device_data.to_json)
173
+ end
174
+
175
+ def max(chunk)
176
+ # TODO
177
+ end
178
+
179
+ def min(chunk)
180
+ # TODO
44
181
  end
45
182
 
46
183
  def write(chunk)
47
- chunk.msgpack_each do |tag, time, record|
48
- $log.debug "#{tag}, #{@formatter.format(tag, time, add_send_time(record)).chomp}\n"
49
- put_message(@formatter.format(tag, time, add_send_time(record)))
184
+ case @aggr_type
185
+ when "none"
186
+ chunk.msgpack_each do |tag, time, record|
187
+ #$log.debug transform_device_data(record["json"]).to_json
188
+ put_message(transform_device_data(record["json"]).to_json)
189
+ end
190
+ when "avg", "max", "min"
191
+ method(@aggr_type).call(chunk)
192
+ else
193
+ raise NotImplementedError, "specified aggr_type is not implemented."
50
194
  end
51
- $log.flush
52
195
  end
53
196
 
54
197
  # This method is called when shutting down.
@@ -6,14 +6,14 @@ Ruby のインタラクティブシェル irb あるいは pry などを利用
6
6
 
7
7
  https://service.every-sense.com で遊ぶためには最低限以下の用語を抑えておく必要があります。
8
8
 
9
- - **ファームオーナー**: EverySenseにアップロードするデータを持っている人。デバイスのクラスを使って自分のデバイスを **ファーム** に登録できます。デバイスを登録すると **デバイスのUUID** を取得できます。
9
+ - **ファームオーナー**: EverySenseにアップロードするデータを持っている人。デバイスのクラスを使って自分のデバイスを **ファーム** に登録できます。デバイスを登録すると **デバイスのUUID** を取得できます。なお、ここで述べているデバイスは、EverySenseサーバ上の仮想デバイスを指します。物理デバイスからのデータアップロード時に取得したデバイスのUUIDを付与することで、物理的なデバイスとEverySenseサーバ上の仮想デバイスを対応づけます。
10
10
  - **レストランオーナー**: EverySenseからデータをダウンロードして活用する人。自分が欲しいデータの条件を **レシピ** として登録し、**レシピのUUID** を取得します。**レシピ** は検索条件で指定した **ファームオーナー** に送ることができます。検索条件はファームオーナーのキーワードから指定できます。
11
- - **デバイスベンダー**: デバイスの開発元やデバイスにとっても詳しいデバイス所有者。デバイスのクラスを定義する権限をもちます。
12
- - **レシピ**: **レストランオーナー** から **ファームオーナー** に送られる欲しいデータの条件。**レストランオーナー** は送られてきたレシピに対してデータを送信しても良いかどうか承認処理を行います。承認されたレシピでは承認した **ファームオーナー** のデバイス or ファーム (?)に送られたデータを取得することができます。
13
- - **デバイスのクラス**: スマートフォンのようにデバイスには複数のセンサが搭載されていると想定されています。デバイスにどのような精度のセンサが搭載されているのか、例えば製品ごとに事前にクラスとして登録しておくことができます。**ファームオーナー** は保持しているデバイスに対応するクラスを選択して、EverySenseに登録することになります。
14
- - **デバイスとセンサ**: **デバイスのクラス** を定義する際には、デバイスに接続された **センサ** を登録する必要があります。1つのデバイスに対して複数の **センサ** が取り付けられることが想定されています。**センサ** は無線接続されたものも含むため、センサごとに設置箇所を登録できます。登録時に指定した **センサ** の名称はデータアップロード時に利用するのでメモしておきましょう。
11
+ - **デバイスベンダー**: 物理デバイスの開発元や物理デバイスにとっても詳しいデバイス所有者。デバイスのクラスを定義する権限をもちます。
12
+ - **レシピ**: **レストランオーナー** から **ファームオーナー** に送られる欲しいデータの条件。**ファームオーナー** は送られてきたレシピに対してデータを送信しても良いかどうか承認処理を行います。必要であれば、さらにレストランオーナー側にも承認プロセスを入れることも可能です。承認されたレシピでは承認した **ファームオーナー** のデバイス(仮想デバイス)またはファーム(複数のデバイスを含むことが可能)に送られたデータを取得することができます。
13
+ - **デバイスのクラス**: スマートフォンのようにデバイスには複数のセンサが搭載されていると想定されています。デバイスにどのような精度のセンサが搭載されているのか、例えば製品ごとに事前にクラスとして登録しておくことができます。**ファームオーナー** は保持している物理デバイスに対応するクラスを選択して、EverySenseに登録することになります。
14
+ - **デバイスとセンサ**: **デバイスのクラス** を定義する際には、物理デバイスに接続された **センサ** を登録する必要があります。1つのデバイスに対して複数の **センサ** が取り付けられることが想定されています。**センサ** は無線接続されたものも含むため、センサごとに設置箇所を登録できます。登録時に指定した **センサ** の名称はデータアップロード時に利用するのでメモしておきましょう。
15
15
 
16
- ![EverySense基礎用語の概説図](https://raw.githubusercontent.com/toyokazu/fluent-plugin-everysense/master/tutorial/ja/images/every-sense-overview.png "EverySense基礎用語の概説図]")
16
+ ![EverySense基礎用語の概説図](https://raw.githubusercontent.com/toyokazu/fluent-plugin-everysense/master/tutorial/ja/images/every-sense-overview.png "EverySense基礎用語の概説図")
17
17
 
18
18
  ## アカウントの登録
19
19
 
@@ -83,9 +83,9 @@ session_req.content_type = 'application/json'
83
83
  session_res = @http.request(session_req)
84
84
  ```
85
85
 
86
- ### デバイスのデータのアップロードとダウンロード
86
+ ### EverySense上の仮想デバイスへのデータのアップロードとダウンロード
87
87
 
88
- 次にデバイスのデータのアップロード、ダウンロードについて試してみるため、テスト用のデバイスを登録してください。以下では仮に TestDevice という名称でデバイスを登録するものとして記述します。なお、デバイスの登録は以下から行えます。
88
+ 次にデバイス(仮想デバイス)へのデータのアップロード、ダウンロードについて試してみるため、テスト用のデバイスを登録してください。以下では仮に TestDevice という名称でデバイスを登録するものとして記述します。なお、デバイスの登録は以下から行えます。
89
89
 
90
90
  https://service.every-sense.com/ja/devices
91
91
 
@@ -98,7 +98,7 @@ https://service.every-sense.com/ja/devices
98
98
 
99
99
  デバイスのデータのアップロード、ダウンロードをする際にUUIDが必要になります。
100
100
 
101
- #### デバイスのデータのアップロード
101
+ #### 仮想デバイスへのデータのアップロード
102
102
 
103
103
  まずはアップロードから試してみましょう。なんと、アップロードには認証は不要です。ということは、デバイスのUUIDを知っている人は誰でもアップロードできてしまうということですね。皆さんUUIDの取り扱いには注意しましょう。
104
104
 
@@ -167,8 +167,10 @@ irb(main):023:0> upload_res.body
167
167
  upload_req.body = [{"data" => {"at" => Time.now.to_s, "unit" => "degree Celsius", "value" => 23}, "sensor_name" => "FESTIVAL_Test1_Sensor"}, {"data" => {"at" => Time.now.to_s, "unit" => "%RH", "value" => 30}, "sensor_name" => "FESTIVAL_Test1_Sensor2"}].to_json
168
168
  ```
169
169
 
170
+ なおEverySenseでは、デバイスから受け取ったデータについて、レシピで指定された取得間隔の中で最初に受け取ったデータを送出するため、受け取ったデータを重複して送出しないように、データを受け取ってから、しばらく後続のデータを待つ仕様になっています。すぐにデータの送出を確認したい場合は、取得間隔の中で複数回データをアップロードしてみてください。
170
171
 
171
- #### デバイスのデータのダウンロード
172
+
173
+ #### 仮想デバイスからのデータのダウンロード
172
174
 
173
175
  データの取得にはログインID (UUID) + パスワードあるいは、session_keyが要求されます。以下では session_key を利用しています。
174
176
 
@@ -226,6 +228,8 @@ recipe_data_res.body
226
228
 
227
229
  取得したデータ中の `"FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"` はファームのUUIDを示しています。
228
230
 
231
+ なお、レシピに対してデバイスからデータが届いているかどうかは、レストランオーナーであれば、「登録中のレシピ」でレシピ一覧を表示し、該当レシピ部分を確認するとダウンロードできるデータの件数が表示されます。また、ファームオーナーであれば、「稼働中のオーダー」から該当レシピのオーダー詳細を参照すると、下部のファーム稼働状況のグラフでデータが送信されているかどうかが確認できます。
232
+
229
233
 
230
234
  ### session_keyの無効化について
231
235
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-everysense
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Toyokazu Akiyama
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-14 00:00:00.000000000 Z
11
+ date: 2016-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd