eeml 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,13 +1,25 @@
1
1
  module Eeml
2
2
  include Eeml::Constants
3
3
 
4
+ # One of the component classes of Environment. Represents the location of the environment. Environments can only have a single location object.
4
5
  class Location
5
6
  attr_accessor :name, :latitude, :longitude, :elevation
6
7
  attr_accessor :domain, :exposure, :disposition
8
+
9
+ def initialize(options = {})
10
+ @name = options[:name]
11
+ @latitude = options[:latitude]
12
+ @longitude = options[:longitude]
13
+ @elevation = options[:elevation]
14
+ @domain = options[:domain]
15
+ @exposure = options[:exposure]
16
+ @disposition = options[:disposition]
17
+ end
7
18
  end
8
19
 
20
+ # One of the component classes of Environment. Represents an individual datastream, and provides access to it's value
21
+ # and other attributes. Environments can have zero or more datastreams.
9
22
  class DataStream
10
- # include FeedOutput::DataStreamNode
11
23
  attr_accessor :identifier, :value, :tags, :min_value, :max_value, :unit_symbol, :unit_type, :unit_value
12
24
 
13
25
  def initialize(options = {})
@@ -26,26 +38,17 @@ module Eeml
26
38
  end
27
39
 
28
40
  end
29
-
41
+
42
+ # This class represents the main point of entry to this library. In general we will be creating instances of this class, either
43
+ # by manually specifying the parameters, or probably more commonly, by passing in either an EEML or JSON formatted string which
44
+ # will be parsed to initialize the object.
30
45
  class Environment
31
- include FeedOutput::EnvironmentNode
32
46
  attr_accessor :identifier, :updated, :creator
33
47
  attr_accessor :title, :description, :feed_url, :website, :email, :icon, :status
34
48
  attr_accessor :location
35
49
  attr_accessor :datastreams
36
50
 
37
- # stuff so far needed only for FeedOutput module
38
- # attr_accessor :retrieved_at
39
-
40
- @@logger = nil
41
- def self.logger=(logger)
42
- @@logger = logger
43
- end
44
-
45
- def logger
46
- return @@logger
47
- end
48
-
51
+ # Create a new Environment object by passing parameters in a hash (just like creating an ActiveRecord object)
49
52
  def initialize(options = {})
50
53
  @datastreams = []
51
54
  @identifier = options[:identifier]
@@ -53,6 +56,10 @@ module Eeml
53
56
  @title = options[:title]
54
57
  @status = options[:status]
55
58
  @feed_url = options[:feed_url]
59
+ @description = options[:description]
60
+ @website = options[:website]
61
+ @email = options[:email]
62
+ @icon = options[:icon]
56
63
  end
57
64
 
58
65
  def add_datastream(datastream)
@@ -64,11 +71,19 @@ module Eeml
64
71
  datastreams.pop
65
72
  end
66
73
 
74
+ # Create multiple Environment objects from an EEML string containing multiple `environment` stanzas.
75
+ def self.new_list_from_eeml(xml_str)
76
+ parser = ParserRegistry.get_xml_parser_for(xml_str)
77
+ return parser.make_environments_from_xml(xml_str)
78
+ end
79
+
80
+ # Create a new Environment object from an EEML string.
67
81
  def self.new_from_eeml(xml_str)
68
82
  parser = ParserRegistry.get_xml_parser_for(xml_str)
69
83
  return parser.make_environment_from_xml(xml_str)
70
84
  end
71
85
 
86
+ # Create a new Environment object from a JSON string.
72
87
  def self.new_from_json(json_str)
73
88
  parser = ParserRegistry.get_json_parser_for(json_str)
74
89
  return parser.make_environment_from_json(json_str)
@@ -95,19 +110,16 @@ module Eeml
95
110
  end
96
111
  end
97
112
 
98
- #--------------------------------------------------------------------------
99
- #----- state tracking stuff -----------------------------------------------
100
- #--------------------------------------------------------------------------
101
- def live?
102
- #TODO
103
- true
104
- end
105
-
106
113
  def to_eeml(version = Constants::EEML_VERSION)
107
114
  outputter = OutputRegistry.get_xml_output_for(version)
108
115
  outputter.to_eeml(self)
109
116
  end
110
117
 
118
+ def to_json
119
+ outputter = OutputRegistry.get_json_output_for
120
+ outputter.to_json(self)
121
+ end
122
+
111
123
  end
112
124
 
113
125
  end
@@ -1,59 +1,63 @@
1
1
  module Eeml
2
- # exceptions
3
- #TODO: have these inherit from a base parser error
4
- class Unavailable < StandardError; end
5
- class BadResponse < StandardError; end
6
- class ApiKeyMissing < StandardError; end
7
- class AuthenticationFailure < StandardError; end
8
-
9
- class BadEeml < StandardError #eeml being parsed was ok xml but bad eeml
10
- attr_accessor :line_num, :node_name #no guarantees either is available
11
- def to_s
12
- extras = []
13
- extras << " node name: '" + node_name + "'" if node_name
14
- extras << " line_num: #{line_num}" if line_num
15
- super.to_s + extras.join(',')
2
+ # Exception classes used by the EEML gem.
3
+ module Exceptions
4
+
5
+ #--
6
+ # TODO: have these inherit from a base parser error
7
+ #++
8
+
9
+ # Eeml being parsed was valid XML, but bad EEML.
10
+ class BadEeml < StandardError
11
+ attr_accessor :line_num, :node_name #no guarantees either is available
12
+ def to_s
13
+ extras = []
14
+ extras << " node name: '" + node_name + "'" if node_name
15
+ extras << " line_num: #{line_num}" if line_num
16
+ super.to_s + extras.join(',')
17
+ end
16
18
  end
17
- end
18
-
19
- class BadXML < StandardError; end #xml being parsed was malformed
20
- class DataMissingValue < BadEeml; end
21
- class DataHasMultipleUnits < BadEeml; end
22
- class DataHasMultipleValues < BadEeml; end
23
- class NoDataStreams < BadEeml; end
24
-
25
-
26
- #A structured exception which holds info about what was missing and from where.
27
- #Note: Some reasons we don't just hold everything in an unstructured exception message:
28
- #1. some bits might be useful for dev but not for the public,
29
- #2. testing is simplified by having the missing node name recorded explicitly (rather than in a human-readable, changeable string).
30
- class MissingNode < BadEeml
31
- attr_accessor :base_node_name, :sought_description, :sought_xpath
32
-
33
- def initialize(base_node_name, sought_description, sought_xpath = nil)
34
- @base_node_name = base_node_name
35
- @sought_description = sought_description
36
- @sought_xpath = sought_xpath
37
- end
38
-
39
- def to_s
40
- "Missing '#@sought_description' node from base node: '#@base_node_name'" +
41
- (@sought_xpath ? "with xpath: '#@sought_xpath'" : "")
42
- end
43
- end
44
-
45
19
 
46
- class MissingAttribute < BadEeml
47
- attr_accessor :node_name, :attribute_name
48
-
49
- def initialize(node_name, attribute_name)
50
- @node_name = node_name
51
- @attribute_name = attribute_name
52
- end
53
-
54
- def to_s
55
- "Missing attribute '#@attribute_name' from node '#@node_name'"
56
- end
57
- end
20
+ # Eeml being parsed was bad XML.
21
+ class BadXML < StandardError; end
22
+ class DataMissingValue < BadEeml; end
23
+ class DataHasMultipleUnits < BadEeml; end
24
+ class DataHasMultipleValues < BadEeml; end
25
+ class NoDataStreams < BadEeml; end
26
+ class MissingNamespace < BadEeml; end
27
+
28
+
29
+ #A structured exception which holds info about what was missing and from where.
30
+ #Note: Some reasons we don't just hold everything in an unstructured exception message:
31
+ #1. some bits might be useful for dev but not for the public,
32
+ #2. testing is simplified by having the missing node name recorded explicitly (rather than in a human-readable, changeable string).
33
+ class MissingNode < BadEeml
34
+ attr_accessor :base_node_name, :sought_description, :sought_xpath
35
+
36
+ def initialize(base_node_name, sought_description, sought_xpath = nil)
37
+ @base_node_name = base_node_name
38
+ @sought_description = sought_description
39
+ @sought_xpath = sought_xpath
40
+ end
41
+
42
+ def to_s
43
+ "Missing '#@sought_description' node from base node: '#@base_node_name'" +
44
+ (@sought_xpath ? "with xpath: '#@sought_xpath'" : "")
45
+ end
46
+ end
47
+
48
+
49
+ class MissingAttribute < BadEeml
50
+ attr_accessor :node_name, :attribute_name
51
+
52
+ def initialize(node_name, attribute_name)
53
+ @node_name = node_name
54
+ @attribute_name = attribute_name
55
+ end
56
+
57
+ def to_s
58
+ "Missing attribute '#@attribute_name' from node '#@node_name'"
59
+ end
60
+ end
61
+ end
58
62
  end
59
63
 
@@ -0,0 +1,69 @@
1
+ module Eeml
2
+ #a parser for json environments
3
+ class JsonEnvironmentParserV005 # :nodoc:
4
+ def make_environment_from_json(json_str)
5
+ env_hash = JSON.parse(json_str)
6
+ env = Environment.new(:title => env_hash["title"],
7
+ :description => env_hash["description"],
8
+ :feed_url => env_hash["feed"],
9
+ :website => env_hash["website"],
10
+ :email => env_hash["email"],
11
+ :icon => env_hash["icon"],
12
+ :status => env_hash["status"],
13
+ :identifier => env_hash["id"])
14
+
15
+ env.updated = Time.mktime(*ParseDate.parsedate(env_hash['updated'])) unless env_hash['updated'].nil?
16
+
17
+ env.location = buildLocation(env_hash)
18
+
19
+ env.datastreams = buildDatastreams(env_hash)
20
+
21
+ return env
22
+ end
23
+
24
+ private
25
+
26
+ def buildLocation(env_hash)
27
+ location_hash = env_hash["location"]
28
+ return if location_hash.nil?
29
+ Location.new(:name => location_hash["name"],
30
+ :latitude => location_hash["lat"],
31
+ :longitude => location_hash["lon"],
32
+ :elevation => location_hash["ele"],
33
+ :domain => location_hash["domain"],
34
+ :disposition => location_hash["disposition"],
35
+ :exposure => location_hash["exposure"])
36
+ end
37
+
38
+ def buildDatastreams(env_hash)
39
+ datastreams_hash = env_hash["datastreams"]
40
+ return if datastreams_hash.nil?
41
+ datastreams = []
42
+ datastreams_hash.each do |datastream_hash|
43
+ datastream = DataStream.new
44
+ raise MissingAttribute.new('id', "data") if datastream_hash['id'].nil?
45
+ datastream.identifier = datastream_hash['id']
46
+ datastream.tags = datastream_hash['tags'] unless datastream_hash['tags'].nil?
47
+
48
+ value_hash = datastream_hash["value"]
49
+ raise DataMissingValue if value_hash.nil?
50
+ # raise DataHasMultipleValues if value_hash.size > 1
51
+ datastream.value = value_hash["current_value"]
52
+ datastream.min_value = value_hash["min_value"]
53
+ datastream.max_value = value_hash["max_value"]
54
+
55
+ unit_hash = datastream_hash["unit"]
56
+ unless unit_hash.nil?
57
+ datastream.unit_symbol = unit_hash["symbol"]
58
+ datastream.unit_type = unit_hash["type"]
59
+ datastream.unit_value = unit_hash["label"]
60
+ end
61
+
62
+ datastreams << datastream
63
+ end
64
+ return datastreams
65
+ end
66
+ end
67
+ end
68
+
69
+
@@ -0,0 +1,86 @@
1
+ module Eeml
2
+
3
+ class JsonOutput # :nodoc:
4
+
5
+ def to_json(environment, options = { :full => true })
6
+ hash = to_public_json_data(environment, options)
7
+ hash.to_json
8
+ end
9
+
10
+ def to_public_json_data(environment, options = { :full => true })
11
+ environment_hash = { :id => Integer(environment.identifier), #we WANT this to fail early when we start using non-numeric identifiers
12
+ :title => environment.title,
13
+ :feed => environment.feed_url,
14
+ :status => environment.status,
15
+ :description => environment.description,
16
+ :website => environment.website,
17
+ :email => environment.email,
18
+ :icon => environment.icon,
19
+ :version => EEML_VERSION}
20
+
21
+ environment_hash[:updated] = environment.updated.strftime("%Y-%m-%dT%H:%M:%SZ") unless environment.updated.nil? #TODO: was retrieved_at
22
+
23
+ environment_hash.delete_if { |key, value| value.blank? }
24
+
25
+ unless environment.location.nil?
26
+
27
+ # add location data
28
+ location_hash = { :domain => environment.location.domain,
29
+ :exposure => environment.location.exposure,
30
+ :disposition => environment.location.disposition,
31
+ :name => environment.location.name,
32
+ :ele => environment.location.elevation #currently, ele is output as a string
33
+ }
34
+ location_hash[:lat] = Float(environment.location.latitude) if environment.location.latitude
35
+ location_hash[:lon] = Float(environment.location.longitude) if environment.location.longitude
36
+
37
+ location_hash.delete_if { |key, value| value.blank? }
38
+
39
+ environment_hash[:location] = location_hash unless location_hash.empty?
40
+ end
41
+
42
+ # if :full option given, add our datastream data into the returned json
43
+ if options[:full] == true
44
+ datastream_array = []
45
+
46
+ # add datastream data
47
+ environment.datastreams.each do |datastream|
48
+ datastream_array << datastream_to_json(datastream)
49
+ end
50
+
51
+ environment_hash[:datastreams] = datastream_array unless datastream_array.empty?
52
+ end
53
+
54
+ return environment_hash
55
+ end
56
+
57
+ protected
58
+ def datastream_to_json(datastream)
59
+ datastream_hash = { :id => datastream.identifier }
60
+
61
+ datastream_hash[:tags] = datastream.tags unless datastream.tags.empty?
62
+
63
+ value_hash = { :min_value => datastream.min_value.to_s,
64
+ :max_value => datastream.max_value.to_s,
65
+ :current_value => datastream.value.to_s }
66
+
67
+ value_hash.delete_if { |key, value| value.blank? }
68
+
69
+ datastream_hash[:value] = value_hash unless value_hash.empty?
70
+
71
+ unit_hash = { :type => datastream.unit_type.to_s,
72
+ :symbol => datastream.unit_symbol.to_s,
73
+ :label => datastream.unit_value.to_s }
74
+
75
+ unit_hash.delete_if { |key, value| value.blank? }
76
+
77
+ datastream_hash[:unit] = unit_hash unless unit_hash.empty?
78
+
79
+ return datastream_hash
80
+ end
81
+
82
+
83
+
84
+ end
85
+ end
86
+
@@ -1,15 +1,28 @@
1
1
  require "parsedate.rb"
2
2
  module Eeml
3
+ include Exceptions
3
4
  #a parser for xml eeml v005, implemented with LibXML
4
5
  class LibXMLEemlParserV005 # :nodoc:
5
6
  include LibXML
6
7
 
7
8
  #main method
8
9
 
9
- #take an xml string, and create an Environment from it
10
- def make_environment_from_xml(xml_str)
10
+ #take an xml string, and create an Environment from it.
11
+ #If an optional environment is given, that will be populated (overwritten) instead of a new environment.
12
+ def make_environment_from_xml(xml_str, given_environment = nil)
11
13
  doc = parse_xml(xml_str)
12
- return extract_environment(doc)
14
+ raise MissingNamespace if doc.root.namespaces.namespace.blank?
15
+ env = given_environment || Environment.new
16
+ #TODO: what has to be reset in a given environment before passing it for re-population?
17
+ return extract_environment_from_doc(doc, env)
18
+ end
19
+
20
+ #take an xml string containing zero or more environment nodes, and create an array of Environment objects from it.
21
+ def make_environments_from_xml(xml_str, given_environment = nil)
22
+ doc = parse_xml(xml_str)
23
+ raise MissingNamespace if doc.root.namespaces.namespace.blank?
24
+ env = Environment.new
25
+ return extract_environments_from_doc(doc)
13
26
  end
14
27
 
15
28
  protected
@@ -39,11 +52,23 @@ module Eeml
39
52
  end
40
53
 
41
54
 
42
- def extract_environment(doc)
43
- env = Environment.new
55
+ #multiple (zero or more)
56
+ def extract_environments_from_doc(doc)
44
57
  doc.root.namespaces.default_prefix = 'x'
58
+ env_nodes = doc.find('x:environment')
59
+ return env_nodes.map{|env_node| new_env = Environment.new; extract_environment_from_node(env_node, new_env)}
60
+ end
45
61
 
62
+ #single, mandatory
63
+ def extract_environment_from_doc(doc, env_to_populate)
64
+ doc.root.namespaces.default_prefix = 'x'
46
65
  env_node = find_first_node_or_fail(doc, 'x:environment', 'environment')
66
+ return extract_environment_from_node(env_node, env_to_populate)
67
+ end
68
+
69
+ #single, from node (everyone uses this to get the work done)
70
+ def extract_environment_from_node(env_node, env_to_populate)
71
+ env = env_to_populate
47
72
  env.identifier = env_node['id']
48
73
  env.updated = Time.mktime(*ParseDate.parsedate(env_node['updated'])) if !env_node['updated'].nil?
49
74
 
@@ -1,12 +1,12 @@
1
1
  module Eeml
2
- class OutputRegistry
2
+ class OutputRegistry # :nodoc:
3
3
  #look at the given xml, build and return a new v005 or 006 parser, accordingly
4
4
  def self.get_xml_output_for(version = EEML_VERSION)
5
5
  LibXMLEemlOutputV005.new
6
6
  end
7
7
 
8
8
  def self.get_json_output_for(version = EEML_VERSION)
9
- JsonEnvironmentParser.new
9
+ JsonOutput.new
10
10
  end
11
11
 
12
12
  end
@@ -1,12 +1,13 @@
1
1
  module Eeml
2
- class ParserRegistry
2
+ class ParserRegistry # :nodoc:
3
3
  #look at the given xml, build and return a new v005 or 006 parser, accordingly
4
+ #this should work whether the xml given is for a single environment, or for a results list
4
5
  def self.get_xml_parser_for(xml_str)
5
6
  LibXMLEemlParserV005.new
6
7
  end
7
8
 
8
9
  def self.get_json_parser_for(json_str)
9
- JsonEnvironmentParser.new
10
+ JsonEnvironmentParserV005.new
10
11
  end
11
12
 
12
13
  end
data/lib/eeml.rb CHANGED
@@ -1,35 +1,28 @@
1
- #TODO: what's going on here and why?
2
- #add this dir to the search path (?)
1
+ # TODO: what's going on here and why?
2
+ # add this dir to the search path (?)
3
3
  $:.unshift(File.dirname(__FILE__))
4
4
 
5
- require 'logger' #std lib
6
5
  require 'blank'
7
6
  require 'libxml'
8
7
  require 'json'
9
8
  require 'eeml/constants'
10
9
  require 'eeml/exceptions'
11
- require 'eeml/feed_output'
12
10
  require 'eeml/environment'
13
11
  require 'eeml/libxml_eeml_parser_v005'
14
- require 'eeml/json_environment_parser'
12
+ require 'eeml/json_environment_parser_v005'
15
13
  require 'eeml/parser_registry'
16
14
  require 'eeml/output_registry'
17
15
  require 'eeml/libxml_eeml_output_v005'
18
-
16
+ require 'eeml/json_output'
19
17
 
20
18
  module Eeml
21
19
 
22
- # enable logger before including everything else, in case we ever want to log initialization
23
- ##TODO: this config should be environment-specific (e.g. test/production). Tests can stub.
24
- Environment.logger = Logger.new(STDERR)
25
-
26
20
  # library version number
27
- VERSION = '0.0.1'
28
- #TODO: put in some configuration file, not here
21
+ VERSION = '0.0.2'
22
+
23
+ # TODO: put in some configuration file, not here
29
24
  LOCAL_EEML_SCHEMA_LOCATION = 'schemas/eeml/005.xsd'
30
25
 
31
26
 
32
27
 
33
28
  end #module
34
-
35
-
data/test/data/doc_1.json CHANGED
@@ -1,2 +1,30 @@
1
- foo
2
-
1
+ {"datastreams":[
2
+ {"tags":["tagD0"],
3
+ "value":{"current_value":"0","min_value":"-9999.0","max_value":"1022.0"},
4
+ "unit":{"type":"basicSI","label":"Celsius","symbol":"C"},
5
+ "id":"0"},
6
+ {"value":{"current_value":"33","min_value":"0.0","max_value":"1023.0"},
7
+ "id":"1"},
8
+ {"tags":["tagD2a","tagD2b","tagD2c"],
9
+ "value":{"current_value":"42.1","min_value":"23.4","max_value":"1021.0"},
10
+ "id":"2"}
11
+ ],
12
+ "description":"description here",
13
+ "updated":"2009-02-11T10:56:56Z",
14
+ "status":"frozen",
15
+ "website":"http:\/\/example.com\/studio\/",
16
+ "email":"someone@example.com",
17
+ "feed":"http:\/\/example.com\/api\/1247.xml",
18
+ "location":{
19
+ "lat":"50.1",
20
+ "lon":"48.7",
21
+ "ele":"1.34",
22
+ "name":"Up on the roof (somewhere)",
23
+ "domain":"physical",
24
+ "exposure":"outdoor",
25
+ "disposition":"mobile"
26
+ },
27
+ "icon":"http:\/\/example.com\/some\/icon.gif",
28
+ "id":"1247",
29
+ "title":"title here",
30
+ "version":"5"}
@@ -0,0 +1,36 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <eeml xmlns="http://www.eeml.org/xsd/005" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="5" xsi:schemaLocation="http://www.eeml.org/xsd/005 http://www.eeml.org/xsd/005/005.xsd">
3
+ <environment updated="2009-04-17T23:59:16Z" id="1044" creator="http://www.haque.co.uk">
4
+ <title>Deployable External Insulation Pavilion</title>
5
+ <feed>http://www.pachube.com/api/1044.xml</feed>
6
+ <status>live</status>
7
+ <description>The Deployable External Insulation (DEI) pavilion is an experimental low-energy pavilion.</description>
8
+ <website>http://www.deployable.org.uk</website>
9
+ <email>chris@example.com</email>
10
+ <location domain="physical" exposure="outdoor" disposition="fixed">
11
+ <name>Shipping Container rooftop Trinity Buoy Wharf</name>
12
+ <lat>51.508255</lat>
13
+ <lon>0.0091516666666667</lon>
14
+ <ele>16.2</ele>
15
+ </location>
16
+ <data id="0">
17
+ <tag>Roof vent wax-piston stroke length</tag>
18
+ <value minValue="137.0" maxValue="932.0">300</value>
19
+ </data>
20
+ <data id="1">
21
+ <tag>Thermal shutter bay one wax-piston stroke length</tag>
22
+ <value minValue="132.0" maxValue="930.0">300</value>
23
+ </data>
24
+ <data id="2">
25
+ <value minValue="0.0" maxValue="0.0">0</value>
26
+ </data>
27
+ <data id="3">
28
+ <tag>Horizontal angle of thermal shutter's opening in front of window bay one (0=fully closed)</tag>
29
+ <value minValue="181.8" maxValue="324.7">200</value>
30
+ </data>
31
+ <data id="4">
32
+ <tag>Air temperature of wax-piston mechanism enclosure</tag>
33
+ <value minValue="5.0" maxValue="27.5">10</value>
34
+ </data>
35
+ </environment>
36
+ </eeml>
@@ -0,0 +1,35 @@
1
+ {"version":"5",
2
+ "description":"The Deployable External Insulation (DEI) pavilion is an experimental low-energy pavilion.",
3
+ "updated":"2009-04-17T23:59:16Z",
4
+ "website":"http:\/\/www.deployable.org.uk",
5
+ "status":"live",
6
+ "title":"Deployable External Insulation Pavilion",
7
+ "location":{
8
+ "lon":0.0091516666666667,
9
+ "exposure":"outdoor",
10
+ "ele":"16.2",
11
+ "name":"Shipping Container rooftop Trinity Buoy Wharf",
12
+ "domain":"physical",
13
+ "lat":51.508255,
14
+ "disposition":"fixed"
15
+ },
16
+ "email":"chris@example.com",
17
+ "feed":"http:\/\/www.pachube.com\/api\/1044.xml",
18
+ "id":1044,
19
+ "datastreams":[
20
+ {"value":{"current_value":"300","min_value":"137.0","max_value":"932.0"},
21
+ "tags":["Roof vent wax-piston stroke length"],
22
+ "id":"0"},
23
+ {"value":{"current_value":"300","min_value":"132.0","max_value":"930.0"},
24
+ "tags":["Thermal shutter bay one wax-piston stroke length"],
25
+ "id":"1"},
26
+ {"value":{"current_value":"0","min_value":"0.0","max_value":"0.0"},
27
+ "id":"2"},
28
+ {"value":{"current_value":"200","min_value":"181.8","max_value":"324.7"},
29
+ "tags":["Horizontal angle of thermal shutter's opening in front of window bay one (0=fully closed)"],
30
+ "id":"3"},
31
+ {"value":{"current_value":"10","min_value":"5.0","max_value":"27.5"},
32
+ "tags":["Air temperature of wax-piston mechanism enclosure"],
33
+ "id":"4"}
34
+ ]
35
+ }
@@ -0,0 +1,38 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <eeml xmlns="http://www.eeml.org/xsd/005" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="5" xsi:schemaLocation="http://www.eeml.org/xsd/005 http://www.eeml.org/xsd/005/005.xsd">
3
+ <environment updated="2009-02-12T05:12:58Z" id="1202" creator="http://www.haque.co.uk">
4
+ <title>Badgerpower</title>
5
+ <feed>http://localhost:3000/api/1202.xml</feed>
6
+ <status>live</status>
7
+ <description>Output from currentcost meter in Badger Towers</description>
8
+ <website>http://example.com/badgerpower</website>
9
+ <location domain="physical" exposure="indoor" disposition="fixed">
10
+ <name>OX4 XXX</name>
11
+ <lat>51.7177447203256</lat>
12
+ <lon>-1.22573090018705</lon>
13
+ </location>
14
+ </environment>
15
+ <environment updated="2009-02-12T05:12:48Z" id="1280" creator="http://www.haque.co.uk">
16
+ <title>CurrentCost for house</title>
17
+ <feed>http://localhost:3000/api/1280.xml</feed>
18
+ <status>live</status>
19
+ <description>Desc of currentcost env</description>
20
+ <website>http://example.com/currentcost</website>
21
+ <location domain="physical" exposure="indoor" disposition="fixed">
22
+ <lat>51.5946518173021</lat>
23
+ <lon>-0.149892568588257</lon>
24
+ </location>
25
+ </environment>
26
+ <environment updated="2009-02-12T05:12:48Z" id="1347" creator="http://www.haque.co.uk">
27
+ <title>Power and Temperature</title>
28
+ <feed>http://localhost:3000/api/1347.xml</feed>
29
+ <status>live</status>
30
+ <website>http://example.com/power</website>
31
+ <location domain="virtual" exposure="indoor" disposition="fixed">
32
+ <name>London, England</name>
33
+ <lat/>
34
+ <lon/>
35
+ </location>
36
+ </environment>
37
+ </eeml>
38
+