flukso4r 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of flukso4r might be problematic. Click here for more details.
- data/README.rdoc +24 -1
- data/Rakefile +2 -1
- data/VERSION +1 -1
- data/bin/flukso_archive_watts +137 -0
- data/bin/flukso_create_db +109 -0
- data/bin/flukso_query +3 -4
- data/lib/flukso/api.rb +1 -19
- data/lib/flukso/database.rb +163 -0
- data/lib/flukso/reading.rb +43 -0
- data/lib/flukso.rb +4 -2
- metadata +18 -2
data/README.rdoc
CHANGED
@@ -11,6 +11,30 @@ meter. A simple call to retrieve the readings of the last day is:
|
|
11
11
|
|
12
12
|
flukso_query -t day -u watt -a <your-sensor-alias>
|
13
13
|
|
14
|
+
In addition, the library includes two scripts that can be used to
|
15
|
+
archive your Flukso readings at the highest resolution. The values are
|
16
|
+
stored in an sqlite3 database.
|
17
|
+
|
18
|
+
First, copy the flukso4rrc template file to a destination of your
|
19
|
+
liking:
|
20
|
+
|
21
|
+
$ cp etc/flukso4rrc $HOME/.flukso4rrc
|
22
|
+
|
23
|
+
Then, edit the file and specify the database file and your API key.
|
24
|
+
Please note that the library uses HTTPS to communicate with the Flukso
|
25
|
+
webservice, so your API key is not sent unencrypted over the net.
|
26
|
+
|
27
|
+
Then, create an empty database:
|
28
|
+
|
29
|
+
$ flukso_create_db -c <CONFIG_FILE>
|
30
|
+
|
31
|
+
After the DB has been created, you can add new data with the command
|
32
|
+
|
33
|
+
$ flukso_archive_watts -c <CONFIG_FILE>
|
34
|
+
|
35
|
+
This command will download all values of the last hour and add the new
|
36
|
+
ones to the database. It is intended to be run as a cronjob.
|
37
|
+
|
14
38
|
The code in lib is a cheap knockoff of the twitter ruby gem - many
|
15
39
|
thanks to John Nunemaker! You can find the twitter ruby gem here:
|
16
40
|
|
@@ -18,7 +42,6 @@ http://twitter.rubyforge.org/
|
|
18
42
|
|
19
43
|
== TODO
|
20
44
|
|
21
|
-
* There is no authentication implemented currently.
|
22
45
|
* Tests of the internals are needed.
|
23
46
|
|
24
47
|
== Note on Patches/Pull Requests
|
data/Rakefile
CHANGED
@@ -11,12 +11,13 @@ begin
|
|
11
11
|
gem.homepage = "http://gonium.net/md/flukso4r"
|
12
12
|
gem.authors = ["Mathias Dalheimer"]
|
13
13
|
gem.bindir = 'bin'
|
14
|
-
gem.executables = ['flukso_query']
|
14
|
+
gem.executables = ['flukso_query', 'flukso_archive_watts', 'flukso_create_db']
|
15
15
|
gem.default_executable = 'flukso_query'
|
16
16
|
gem.files = FileList["[A-Z]*", "{bin,lib,test}/**/*"]
|
17
17
|
|
18
18
|
#gem.add_dependency('oauth', '~> 0.3.6')
|
19
19
|
gem.add_dependency('httparty', '~> 0.4.3')
|
20
|
+
gem.add_dependency('sqlite3-ruby', '~> 1.2.5')
|
20
21
|
#gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
21
22
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
22
23
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
@@ -0,0 +1,137 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
###
|
3
|
+
##
|
4
|
+
# flukso4r: A Ruby library for Flukso
|
5
|
+
# Copyright (C) 2010 Mathias Dalheimer (md@gonium.net)
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation; either version 2 of the License, or
|
10
|
+
# any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License along
|
18
|
+
# with this program; if not, write to the Free Software Foundation, Inc.,
|
19
|
+
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
20
|
+
##
|
21
|
+
###
|
22
|
+
|
23
|
+
# Read the flukso4r location
|
24
|
+
libpath=File.join(File.dirname(__FILE__), '..', 'lib')
|
25
|
+
$:.unshift << libpath
|
26
|
+
#puts "Using libraty path #{$:.join(":")}"
|
27
|
+
|
28
|
+
require 'flukso'
|
29
|
+
require 'optparse'
|
30
|
+
require 'ostruct'
|
31
|
+
|
32
|
+
###
|
33
|
+
## Commandline parser
|
34
|
+
#
|
35
|
+
class Optparser
|
36
|
+
CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary]
|
37
|
+
CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
|
38
|
+
#
|
39
|
+
# Return a structure describing the options.
|
40
|
+
#
|
41
|
+
def self.parse(args)
|
42
|
+
# The options specified on the command line will be collected in *options*.
|
43
|
+
# We set default values here.
|
44
|
+
options = OpenStruct.new
|
45
|
+
options.inplace = false
|
46
|
+
options.encoding = "utf8"
|
47
|
+
options.verbose = false
|
48
|
+
opts = OptionParser.new do |opts|
|
49
|
+
opts.banner = "Usage: #{$0} [options]"
|
50
|
+
opts.separator ""
|
51
|
+
opts.separator "Specific options:"
|
52
|
+
opts.on("-c", "--config FILE", "The file where the configuration lives.") do |file|
|
53
|
+
options.config_file = file
|
54
|
+
end
|
55
|
+
# Boolean switch.
|
56
|
+
opts.on("-v", "--verbose", "Run verbosely") do |v|
|
57
|
+
options.verbose = v
|
58
|
+
end
|
59
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
60
|
+
puts opts
|
61
|
+
exit
|
62
|
+
end
|
63
|
+
end
|
64
|
+
opts.parse!(args)
|
65
|
+
options
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
###
|
70
|
+
## Script startup
|
71
|
+
#
|
72
|
+
options = Optparser.parse(ARGV)
|
73
|
+
$verbose = options.verbose
|
74
|
+
if options.config_file == nil
|
75
|
+
puts "Please provide a configuration file... (-h for details)."
|
76
|
+
exit(-1);
|
77
|
+
end
|
78
|
+
if not File.exists?(options.config_file)
|
79
|
+
puts " Configuration file #{options.config_file} not found - no database configuration available!"
|
80
|
+
exit(-3);
|
81
|
+
else
|
82
|
+
$CONFIG=YAML.load_file(options.config_file);
|
83
|
+
puts "Using this configuration:" if $verbose
|
84
|
+
puts "#{$CONFIG}" if $verbose
|
85
|
+
dbfile=$CONFIG['DB_FILE']
|
86
|
+
end
|
87
|
+
if $verbose
|
88
|
+
puts " Using database file #{dbfile}"
|
89
|
+
end
|
90
|
+
# check and expand paths.
|
91
|
+
if not File.exists?(dbfile)
|
92
|
+
puts " Database does not exist - please create one. Aborting."
|
93
|
+
exit(-2);
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
# No authentication by now.
|
98
|
+
auth=Flukso::HTTPAuth.new("", "");
|
99
|
+
api=Flukso::API.new(auth);
|
100
|
+
query=Flukso::QueryReadings.new($CONFIG["ACCESS_KEY"], :hour, :watt)
|
101
|
+
begin
|
102
|
+
readings=query.execute(api);
|
103
|
+
rescue Exception => e
|
104
|
+
puts "Query failed: #{e}"
|
105
|
+
exit(-10);
|
106
|
+
end
|
107
|
+
|
108
|
+
# Remove NaN elements - NaN Handling in Ruby sucks.
|
109
|
+
clean_readings = readings.map{|reading|
|
110
|
+
#puts "checking #{reading.value} of class #{reading.value.class}"
|
111
|
+
if reading.value.class==Float
|
112
|
+
if reading.value.nan?
|
113
|
+
nil;
|
114
|
+
else
|
115
|
+
reading
|
116
|
+
end
|
117
|
+
else
|
118
|
+
reading;
|
119
|
+
end
|
120
|
+
}.compact
|
121
|
+
|
122
|
+
if $verbose
|
123
|
+
clean_readings.each{|reading|
|
124
|
+
puts reading
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
db=Flukso::FluksoDB.open($CONFIG["DB_FILE"], $CONFIG["DB_TABLE_NAME"]);
|
129
|
+
begin
|
130
|
+
last=db.find_reading_last();
|
131
|
+
puts "Last reading: #{last}"
|
132
|
+
rescue Flukso::ElementNotFoundError => e
|
133
|
+
puts "Empty database - not able to provide last reading."
|
134
|
+
end
|
135
|
+
insertCount = db.appendNewReadings(clean_readings);
|
136
|
+
puts "Added #{insertCount} new readings to the database."
|
137
|
+
db.close
|
@@ -0,0 +1,109 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This file is part of fluksobot
|
3
|
+
# (c) 2009 Mathias Dalheimer, md@gonium.net
|
4
|
+
#
|
5
|
+
# FluksoBot is free software; you can
|
6
|
+
# redistribute it and/or modify it under the terms of the GNU General Public
|
7
|
+
# License as published by the Free Software Foundation; either version 2 of
|
8
|
+
# the License, or any later version.
|
9
|
+
#
|
10
|
+
# FluksoBot is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with FluksoBot; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
|
19
|
+
# Read the fluksobot location
|
20
|
+
libpath=File.join(File.dirname(__FILE__), '..', 'lib')
|
21
|
+
$:.unshift << libpath
|
22
|
+
#puts "Using libraty path #{$:.join(":")}"
|
23
|
+
|
24
|
+
require 'rubygems'
|
25
|
+
require 'optparse'
|
26
|
+
require 'ostruct'
|
27
|
+
require 'flukso'
|
28
|
+
|
29
|
+
###
|
30
|
+
## Commandline parser
|
31
|
+
#
|
32
|
+
class Optparser
|
33
|
+
CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary]
|
34
|
+
CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
|
35
|
+
#
|
36
|
+
# Return a structure describing the options.
|
37
|
+
#
|
38
|
+
def self.parse(args)
|
39
|
+
# The options specified on the command line will be collected in *options*.
|
40
|
+
# We set default values here.
|
41
|
+
options = OpenStruct.new
|
42
|
+
options.inplace = false
|
43
|
+
options.encoding = "utf8"
|
44
|
+
options.verbose = false
|
45
|
+
opts = OptionParser.new do |opts|
|
46
|
+
opts.banner = "Usage: #{$0} [options]"
|
47
|
+
opts.separator ""
|
48
|
+
opts.separator "Specific options:"
|
49
|
+
opts.on("-c", "--config FILE", "The configuration file to use.") do |file|
|
50
|
+
options.config_file = file
|
51
|
+
end
|
52
|
+
# Boolean switch.
|
53
|
+
opts.on("-f", "--force", "Ignore warnings") do |f|
|
54
|
+
options.force = f
|
55
|
+
end
|
56
|
+
opts.on("-v", "--verbose", "Run verbosely") do |v|
|
57
|
+
options.verbose = v
|
58
|
+
end
|
59
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
60
|
+
puts opts
|
61
|
+
exit
|
62
|
+
end
|
63
|
+
end
|
64
|
+
opts.parse!(args)
|
65
|
+
options
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
###
|
70
|
+
## Script startup
|
71
|
+
#
|
72
|
+
options = Optparser.parse(ARGV)
|
73
|
+
$verbose = options.verbose
|
74
|
+
$force = options.force
|
75
|
+
puts "FluksoBot database setup script."
|
76
|
+
if options.config_file == nil
|
77
|
+
puts "Please provide a configuration file... (-h for details)."
|
78
|
+
exit(-1);
|
79
|
+
end
|
80
|
+
if not File.exists?(options.config_file)
|
81
|
+
puts " Configuration file #{options.config_file} not found - no database configuration available!"
|
82
|
+
exit(-3);
|
83
|
+
else
|
84
|
+
$CONFIG=YAML.load_file(options.config_file);
|
85
|
+
puts "Using this configuration:" if $verbose
|
86
|
+
puts "#{$CONFIG}" if $verbose
|
87
|
+
dbfile=$CONFIG['DB_FILE']
|
88
|
+
end
|
89
|
+
if $verbose
|
90
|
+
puts " Using database file #{dbfile}"
|
91
|
+
end
|
92
|
+
# check and expand paths.
|
93
|
+
if File.exists?(dbfile) and not $force
|
94
|
+
puts " Database already exists. Aborting."
|
95
|
+
exit(-2);
|
96
|
+
end
|
97
|
+
|
98
|
+
# The database does not exist. Create the DB and populate it with
|
99
|
+
# tables.
|
100
|
+
begin
|
101
|
+
db=Flukso::FluksoDB.create(dbfile, $CONFIG['DB_TABLE_NAME']);
|
102
|
+
db.close();
|
103
|
+
puts "Success."
|
104
|
+
rescue Exception => e
|
105
|
+
puts "Failed to initialize db: #{e}"
|
106
|
+
puts "Backtrace:" if $verbose
|
107
|
+
puts e.backtrace if $verbose
|
108
|
+
end
|
109
|
+
|
data/bin/flukso_query
CHANGED
@@ -49,15 +49,12 @@ class Optparser
|
|
49
49
|
opts.banner = "Usage: #{$0} [options]"
|
50
50
|
opts.separator ""
|
51
51
|
opts.separator "Specific options:"
|
52
|
-
opts.on("-t", "--timerange VALUE", "The time range you want to query. Valid queries are: {hour, day, month, year}") do |timerange|
|
52
|
+
opts.on("-t", "--timerange VALUE", "The time range you want to query. Valid queries are: {hour, day, month, year, night}") do |timerange|
|
53
53
|
options.timerange = timerange
|
54
54
|
end
|
55
55
|
opts.on("-u", "--unit VALUE", "The unit you want to query. Valid queries are: {watt, kwh, eur, aud}") do |unit|
|
56
56
|
options.unit = unit
|
57
57
|
end
|
58
|
-
opts.on("-u", "--unit VALUE", "The unit you want to query. Valid queries are: {watt, kwh, eur, aud}") do |unit|
|
59
|
-
options.unit = unit
|
60
|
-
end
|
61
58
|
opts.on("-a", "--alias VALUE", "The device alias you want to query.") do |alias_id|
|
62
59
|
options.alias_id = alias_id
|
63
60
|
end
|
@@ -89,6 +86,8 @@ when /^month$/i
|
|
89
86
|
range=:month
|
90
87
|
when /^year$/i
|
91
88
|
range=:year
|
89
|
+
when /^night$/i
|
90
|
+
range=:night
|
92
91
|
else begin
|
93
92
|
puts "Invalid timerange: #{options.timerange} - see -h for more information."
|
94
93
|
exit(-1);
|
data/lib/flukso/api.rb
CHANGED
@@ -25,7 +25,7 @@ module Flukso
|
|
25
25
|
def initialize(alias_id, timerange=:hour, unit=:watt)
|
26
26
|
@alias_id=alias_id;
|
27
27
|
# sanity checks.
|
28
|
-
valid_timeranges=[:hour, :day, :month, :year];
|
28
|
+
valid_timeranges=[:hour, :day, :month, :year, :night];
|
29
29
|
valid_units=[:watt, :kwh, :eur, :aud];
|
30
30
|
raise Flukso::General, "Invalid timerange #{timerange}" unless valid_timeranges.include?(timerange);
|
31
31
|
raise Flukso::General, "Invalid unit #{unit}" unless valid_units.include?(unit);
|
@@ -52,24 +52,6 @@ module Flukso
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
class UTCReading
|
56
|
-
attr_accessor :utc_timestamp, :value
|
57
|
-
def initialize(utc_timestamp, value)
|
58
|
-
# sanity checks.
|
59
|
-
raise Flukso::General, "Invalid reading timestamp: #{utc_timestamp}" if utc_timestamp < 0;
|
60
|
-
#raise Flukso::General, "Invalid reading value: #{value}" if value.class != Fixnum || value < 0;
|
61
|
-
@utc_timestamp = utc_timestamp.to_i;
|
62
|
-
if value =~ /^nan$/i
|
63
|
-
@value=0.0/0.0 # Workaround: Ruby does not allow to assign NaN directly.
|
64
|
-
else
|
65
|
-
@value = value
|
66
|
-
end
|
67
|
-
end
|
68
|
-
def to_s
|
69
|
-
return "#{@utc_timestamp} -> #{@value}"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
55
|
class API
|
74
56
|
extend Forwardable
|
75
57
|
|
@@ -0,0 +1,163 @@
|
|
1
|
+
###
|
2
|
+
##
|
3
|
+
# flukso4r: A Ruby library for Flukso
|
4
|
+
# (c) 2010 Mathias Dalheimer, md@gonium.net
|
5
|
+
#
|
6
|
+
# Flukso4r is free software; you can
|
7
|
+
# redistribute it and/or modify it under the terms of the GNU General Public
|
8
|
+
# License as published by the Free Software Foundation; either version 2 of
|
9
|
+
# the License, or any later version.
|
10
|
+
#
|
11
|
+
# Flukso4r is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with CGWG; if not, write to the Free Software
|
18
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
19
|
+
|
20
|
+
module Flukso
|
21
|
+
require 'sqlite3'
|
22
|
+
require 'flukso'
|
23
|
+
|
24
|
+
DB_SCHEMA=<<-SQL
|
25
|
+
create table :::TABLE_NAME::: (
|
26
|
+
EPOCHTIME integer primary key,
|
27
|
+
VALUE integer not null
|
28
|
+
);
|
29
|
+
SQL
|
30
|
+
|
31
|
+
|
32
|
+
class FluksoDB
|
33
|
+
# create a new database
|
34
|
+
def self.create(filename, tablename)
|
35
|
+
filename=String.new(File.expand_path(filename));
|
36
|
+
if File.exists?(filename)
|
37
|
+
raise "Database file #{filename} already exists."
|
38
|
+
end
|
39
|
+
puts "Creating new database file #{filename}" if $verbose
|
40
|
+
db = SQLite3::Database.open(filename)
|
41
|
+
schema = FluksoDB.fill_template( DB_SCHEMA, { 'TABLE_NAME' => tablename} )
|
42
|
+
db.execute_batch(schema)
|
43
|
+
return FluksoDB.new(db, tablename);
|
44
|
+
end
|
45
|
+
# open an existing database
|
46
|
+
def self.open(filename, tablename)
|
47
|
+
filename=File.expand_path(filename);
|
48
|
+
if not File.exists?(filename)
|
49
|
+
raise "Database file #{filename} does not exist."
|
50
|
+
end
|
51
|
+
db = SQLite3::Database.open( filename)
|
52
|
+
return FluksoDB.new(db, tablename);
|
53
|
+
end
|
54
|
+
# See: http://freshmeat.net/articles/templates-in-ruby
|
55
|
+
# template: Returns a string formed from a template and replacement values
|
56
|
+
#
|
57
|
+
# templateStr - The template string (format shown below)
|
58
|
+
# values - A hash of replacement values
|
59
|
+
#
|
60
|
+
# Example format:
|
61
|
+
# "Dear :::customer:::,\nPlease pay us :::amount:::.\n"
|
62
|
+
#
|
63
|
+
# The "customer" and "amount" strings are used as keys to index against the
|
64
|
+
# values hash.
|
65
|
+
#
|
66
|
+
def self.fill_template( templateStr, values )
|
67
|
+
outStr = templateStr.clone()
|
68
|
+
values.keys.each { |key|
|
69
|
+
outStr.gsub!( /:::#{key}:::/, values[ key ] )
|
70
|
+
}
|
71
|
+
outStr
|
72
|
+
end
|
73
|
+
# constuctor: give SQLite::Database object as argument. see class
|
74
|
+
# methods.
|
75
|
+
def initialize(db, tablename)
|
76
|
+
@tablename=tablename
|
77
|
+
@db=db;
|
78
|
+
@db.results_as_hash = true
|
79
|
+
end
|
80
|
+
def close
|
81
|
+
@db.close;
|
82
|
+
end
|
83
|
+
# Appends the readings of the provided array to the database.
|
84
|
+
def appendNewReadings(readings)
|
85
|
+
insertCounter=0
|
86
|
+
last_timestamp=0
|
87
|
+
begin
|
88
|
+
last_reading=find_reading_last();
|
89
|
+
last_timestamp=last_reading.utc_timestamp;
|
90
|
+
rescue Flukso::ElementNotFoundError => e
|
91
|
+
puts "Empty database - not able to provide last reading."
|
92
|
+
end
|
93
|
+
readings.each{|reading|
|
94
|
+
if reading.utc_timestamp > last_timestamp
|
95
|
+
puts "Appending #{reading}" if $verbose
|
96
|
+
storeReading(reading);
|
97
|
+
insertCounter += 1
|
98
|
+
else
|
99
|
+
puts "Skipping reading at #{reading.utc_timestamp}, already in DB." if $verbose
|
100
|
+
end
|
101
|
+
}
|
102
|
+
return insertCounter
|
103
|
+
end
|
104
|
+
def storeReading(reading)
|
105
|
+
# TODO: Make this more efficient, recycle insert statements.
|
106
|
+
if reading.class != UTCReading
|
107
|
+
raise "Must give a UTCReading instance."
|
108
|
+
end
|
109
|
+
stmt=<<-SQL
|
110
|
+
INSERT INTO #{@tablename}
|
111
|
+
VALUES ('#{reading.utc_timestamp}', '#{reading.value}');
|
112
|
+
SQL
|
113
|
+
@db.execute(stmt)
|
114
|
+
end
|
115
|
+
def find_reading_last_five
|
116
|
+
return find_last_reading(5);
|
117
|
+
end
|
118
|
+
def find_reading_last
|
119
|
+
return find_last_reading(1)[0];
|
120
|
+
end
|
121
|
+
def find_last_reading(amount)
|
122
|
+
if not amount.class==Fixnum
|
123
|
+
raise "Must provide the number of last readings desired as an Fixnum."
|
124
|
+
end
|
125
|
+
stmt=<<-SQL
|
126
|
+
SELECT * FROM #{@tablename}
|
127
|
+
order by epochtime DESC limit #{amount};
|
128
|
+
SQL
|
129
|
+
#puts "Using statement #{stmt}" if $verbose
|
130
|
+
readings=Array.new
|
131
|
+
@db.execute(stmt) {|row|
|
132
|
+
value=row['VALUE'].to_f;
|
133
|
+
#timestamp=Time.at(row['EPOCHTIME'].to_f);
|
134
|
+
timestamp=row['EPOCHTIME'].to_f;
|
135
|
+
#puts "Creating new UTCReading: #{timestamp}, #{value}"
|
136
|
+
reading=UTCReading.new(timestamp, value);
|
137
|
+
readings << reading
|
138
|
+
}
|
139
|
+
if readings.empty?
|
140
|
+
raise ElementNotFoundError
|
141
|
+
end
|
142
|
+
return readings;
|
143
|
+
end
|
144
|
+
def find_reading_by_epochtime(time)
|
145
|
+
stmt=<<-SQL
|
146
|
+
SELECT * FROM #{@tablename}
|
147
|
+
WHERE epochtime ='#{time}';
|
148
|
+
SQL
|
149
|
+
readings=Array.new
|
150
|
+
@db.execute(stmt) {|row|
|
151
|
+
reading=UTCReading.new(row['TIMESTAMP'].to_i, row['VALUE'].to_i)
|
152
|
+
readings << reading
|
153
|
+
}
|
154
|
+
if readings.empty?
|
155
|
+
raise ElementNotFoundError
|
156
|
+
end
|
157
|
+
return readings[0];
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class ElementNotFoundError < RuntimeError
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
###
|
2
|
+
##
|
3
|
+
# flukso4r: A Ruby library for Flukso
|
4
|
+
# Copyright (C) 2010 Mathias Dalheimer (md@gonium.net)
|
5
|
+
#
|
6
|
+
# This program is free software; you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation; either version 2 of the License, or
|
9
|
+
# any later version.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License along
|
17
|
+
# with this program; if not, write to the Free Software Foundation, Inc.,
|
18
|
+
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
19
|
+
##
|
20
|
+
###
|
21
|
+
|
22
|
+
|
23
|
+
module Flukso
|
24
|
+
|
25
|
+
class UTCReading
|
26
|
+
attr_accessor :utc_timestamp, :value
|
27
|
+
def initialize(utc_timestamp, value)
|
28
|
+
# sanity checks.
|
29
|
+
raise Flukso::General, "Invalid reading timestamp: #{utc_timestamp}" if utc_timestamp < 0;
|
30
|
+
#raise Flukso::General, "Invalid reading value: #{value}" if value.class != Fixnum || value < 0;
|
31
|
+
@utc_timestamp = utc_timestamp.to_i;
|
32
|
+
if value =~ /^nan$/i
|
33
|
+
@value=0.0/0.0 # Workaround: Ruby does not allow to assign NaN directly.
|
34
|
+
else
|
35
|
+
@value = value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
def to_s
|
39
|
+
return "#{@utc_timestamp} -> #{@value}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/lib/flukso.rb
CHANGED
@@ -43,12 +43,14 @@ module Flukso
|
|
43
43
|
class Unavailable < StandardError; end
|
44
44
|
class InformFlukso < StandardError; end
|
45
45
|
class NotFound < StandardError; end
|
46
|
-
|
47
|
-
BASE_SENSOR_URL = "
|
46
|
+
# Use only the encrypted endpoint.
|
47
|
+
BASE_SENSOR_URL = "https://api.flukso.net/sensor"
|
48
48
|
end
|
49
49
|
|
50
50
|
directory = File.expand_path(File.dirname(__FILE__))
|
51
51
|
|
52
52
|
require File.join(directory, 'flukso', 'http_auth')
|
53
|
+
require File.join(directory, 'flukso', 'reading')
|
53
54
|
require File.join(directory, 'flukso', 'request')
|
54
55
|
require File.join(directory, 'flukso', 'api')
|
56
|
+
require File.join(directory, 'flukso', 'database')
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flukso4r
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mathias Dalheimer
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-02-15 00:00:00 +01:00
|
13
13
|
default_executable: flukso_query
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -22,10 +22,22 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: 0.4.3
|
24
24
|
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: sqlite3-ruby
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.2.5
|
34
|
+
version:
|
25
35
|
description: This gem provides a library for the Flukso API. See http://flukso.net for more information.
|
26
36
|
email: md@gonium.net
|
27
37
|
executables:
|
28
38
|
- flukso_query
|
39
|
+
- flukso_archive_watts
|
40
|
+
- flukso_create_db
|
29
41
|
extensions: []
|
30
42
|
|
31
43
|
extra_rdoc_files:
|
@@ -36,10 +48,14 @@ files:
|
|
36
48
|
- README.rdoc
|
37
49
|
- Rakefile
|
38
50
|
- VERSION
|
51
|
+
- bin/flukso_archive_watts
|
52
|
+
- bin/flukso_create_db
|
39
53
|
- bin/flukso_query
|
40
54
|
- lib/flukso.rb
|
41
55
|
- lib/flukso/api.rb
|
56
|
+
- lib/flukso/database.rb
|
42
57
|
- lib/flukso/http_auth.rb
|
58
|
+
- lib/flukso/reading.rb
|
43
59
|
- lib/flukso/request.rb
|
44
60
|
- test/helper.rb
|
45
61
|
- test/test_flukso4r.rb
|