eeml 0.0.1 → 0.0.2

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.
@@ -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
+