trigger_switch_d 0.1.0

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.
Files changed (133) hide show
  1. data/COPYING.txt +674 -0
  2. data/LICENSE.txt +54 -0
  3. data/README.rdoc +106 -0
  4. data/bin/teach +44 -0
  5. data/bin/tsd +68 -0
  6. data/bin/turn_off +42 -0
  7. data/bin/turn_on +39 -0
  8. data/doc/classes/Tellstick/Tellstick.html +117 -0
  9. data/doc/classes/Tellstick/TellstickIO.html +265 -0
  10. data/doc/classes/Tellstick/TellstickIO.src/M000020.html +18 -0
  11. data/doc/classes/Tellstick/TellstickIO.src/M000021.html +20 -0
  12. data/doc/classes/Tellstick/TellstickIO.src/M000022.html +26 -0
  13. data/doc/classes/Tellstick/TellstickIO.src/M000023.html +19 -0
  14. data/doc/classes/Tellstick/TellstickIO.src/M000024.html +26 -0
  15. data/doc/classes/Tellstick/TellstickIO.src/M000025.html +16 -0
  16. data/doc/classes/Tellstick/TellstickIO.src/M000026.html +16 -0
  17. data/doc/classes/Tellstick/TellstickIO.src/M000027.html +24 -0
  18. data/doc/classes/Tellstick.html +204 -0
  19. data/doc/classes/Tellstick.src/M000019.html +25 -0
  20. data/doc/classes/TriggerSwitchD/Action.html +165 -0
  21. data/doc/classes/TriggerSwitchD/Action.src/M000015.html +28 -0
  22. data/doc/classes/TriggerSwitchD/Action.src/M000016.html +18 -0
  23. data/doc/classes/TriggerSwitchD/Application.html +203 -0
  24. data/doc/classes/TriggerSwitchD/Application.src/M000017.html +21 -0
  25. data/doc/classes/TriggerSwitchD/Application.src/M000018.html +40 -0
  26. data/doc/classes/TriggerSwitchD/ConfigFactory/Config.html +127 -0
  27. data/doc/classes/TriggerSwitchD/ConfigFactory/Config.src/M000014.html +23 -0
  28. data/doc/classes/TriggerSwitchD/ConfigFactory.html +141 -0
  29. data/doc/classes/TriggerSwitchD/ConfigFactory.src/M000013.html +24 -0
  30. data/doc/classes/TriggerSwitchD/IPC.html +134 -0
  31. data/doc/classes/TriggerSwitchD/IPC.src/M000012.html +32 -0
  32. data/doc/classes/TriggerSwitchD/Schedule/InstanceMethods.html +242 -0
  33. data/doc/classes/TriggerSwitchD/Schedule/InstanceMethods.src/M000005.html +19 -0
  34. data/doc/classes/TriggerSwitchD/Schedule/InstanceMethods.src/M000006.html +18 -0
  35. data/doc/classes/TriggerSwitchD/Schedule/InstanceMethods.src/M000007.html +23 -0
  36. data/doc/classes/TriggerSwitchD/Schedule/InstanceMethods.src/M000008.html +19 -0
  37. data/doc/classes/TriggerSwitchD/Schedule/InstanceMethods.src/M000009.html +19 -0
  38. data/doc/classes/TriggerSwitchD/Schedule/InstanceMethods.src/M000010.html +18 -0
  39. data/doc/classes/TriggerSwitchD/Schedule/InstanceMethods.src/M000011.html +18 -0
  40. data/doc/classes/TriggerSwitchD/Schedule.html +147 -0
  41. data/doc/classes/TriggerSwitchD/Schedule.src/M000004.html +19 -0
  42. data/doc/classes/TriggerSwitchD/SwitchFactory.html +135 -0
  43. data/doc/classes/TriggerSwitchD/SwitchFactory.src/M000003.html +20 -0
  44. data/doc/classes/TriggerSwitchD.html +212 -0
  45. data/doc/classes/TriggerSwitchD.src/M000001.html +22 -0
  46. data/doc/classes/TriggerSwitchD.src/M000002.html +27 -0
  47. data/doc/created.rid +1 -0
  48. data/doc/files/lib/tellstick/protocol/nexa_rb.html +126 -0
  49. data/doc/files/lib/tellstick/protocol/not_connected_rb.html +126 -0
  50. data/doc/files/lib/tellstick/protocol/null_protocol_rb.html +126 -0
  51. data/doc/files/lib/tellstick/protocol/plain_text_rb.html +126 -0
  52. data/doc/files/lib/tellstick/protocol/proove_rb.html +126 -0
  53. data/doc/files/lib/tellstick/protocol/protocol_loader_rb.html +126 -0
  54. data/doc/files/lib/tellstick/protocol/rising_sun_rb.html +126 -0
  55. data/doc/files/lib/tellstick/protocol/waveman_rb.html +126 -0
  56. data/doc/files/lib/tellstick/tellstick_io_rb.html +135 -0
  57. data/doc/files/lib/tellstick/tellstick_rb.html +135 -0
  58. data/doc/files/lib/tellstick_rb.html +134 -0
  59. data/doc/files/lib/trigger_switch_d/action_rb.html +126 -0
  60. data/doc/files/lib/trigger_switch_d/application_rb.html +136 -0
  61. data/doc/files/lib/trigger_switch_d/config_rb.html +126 -0
  62. data/doc/files/lib/trigger_switch_d/daylight_rb.html +126 -0
  63. data/doc/files/lib/trigger_switch_d/ipc_rb.html +126 -0
  64. data/doc/files/lib/trigger_switch_d/schedule_rb.html +126 -0
  65. data/doc/files/lib/trigger_switch_d/switch_rb.html +126 -0
  66. data/doc/files/lib/trigger_switch_d/trigger_switch_d_helper_rb.html +126 -0
  67. data/doc/files/lib/trigger_switch_d_rb.html +140 -0
  68. data/doc/fr_class_index.html +38 -0
  69. data/doc/fr_file_index.html +46 -0
  70. data/doc/fr_method_index.html +53 -0
  71. data/doc/index.html +24 -0
  72. data/features/execute_schedule.feature +20 -0
  73. data/features/group_aliases.feature +31 -0
  74. data/features/handle_switches.feature +36 -0
  75. data/features/listen_for_client_call.feature +23 -0
  76. data/features/persistent_schedule.feature +70 -0
  77. data/features/proove_protocol.feature +20 -0
  78. data/features/schedule.feature +25 -0
  79. data/features/simple_string_protocol.feature +35 -0
  80. data/features/step_definitions/execute_schedule_steps.rb +16 -0
  81. data/features/step_definitions/group_aliases_steps.rb +24 -0
  82. data/features/step_definitions/handle_switches_steps.rb +21 -0
  83. data/features/step_definitions/listen_for_client_call_steps.rb +34 -0
  84. data/features/step_definitions/persistent_schedule_steps.rb +18 -0
  85. data/features/step_definitions/proove_protocol_steps.rb +3 -0
  86. data/features/step_definitions/schedule_steps.rb +9 -0
  87. data/features/step_definitions/shared_steps.rb +75 -0
  88. data/features/step_definitions/simple_string_protocol_steps.rb +3 -0
  89. data/features/step_definitions/sunrise_steps.rb +22 -0
  90. data/features/step_definitions/tellstick_connected_steps.rb +21 -0
  91. data/features/sunrise.feature +22 -0
  92. data/features/sunset.feature +22 -0
  93. data/features/support/action_helpers.rb +10 -0
  94. data/features/support/env.rb +7 -0
  95. data/features/support/listen_for_client_call_helper.rb +71 -0
  96. data/features/support/proove_helpers.rb +6 -0
  97. data/features/support/sunrise_helper.rb +8 -0
  98. data/features/tellstick_connected.feature +14 -0
  99. data/lib/tellstick/protocol/nexa.rb +48 -0
  100. data/lib/tellstick/protocol/not_connected.rb +42 -0
  101. data/lib/tellstick/protocol/null_protocol.rb +41 -0
  102. data/lib/tellstick/protocol/plain_text.rb +35 -0
  103. data/lib/tellstick/protocol/proove.rb +83 -0
  104. data/lib/tellstick/protocol/protocol_loader.rb +26 -0
  105. data/lib/tellstick/protocol/rising_sun.rb +42 -0
  106. data/lib/tellstick/protocol/waveman.rb +29 -0
  107. data/lib/tellstick/tellstick.rb +73 -0
  108. data/lib/tellstick/tellstick_io.rb +80 -0
  109. data/lib/tellstick.rb +20 -0
  110. data/lib/trigger_switch_d/action.rb +83 -0
  111. data/lib/trigger_switch_d/application.rb +89 -0
  112. data/lib/trigger_switch_d/config.rb +83 -0
  113. data/lib/trigger_switch_d/daylight.rb +114 -0
  114. data/lib/trigger_switch_d/ipc.rb +39 -0
  115. data/lib/trigger_switch_d/schedule.rb +95 -0
  116. data/lib/trigger_switch_d/switch.rb +37 -0
  117. data/lib/trigger_switch_d/trigger_switch_d_helper.rb +44 -0
  118. data/lib/trigger_switch_d.rb +26 -0
  119. data/spec/spec_helper.rb +22 -0
  120. data/spec/tellstick/protocol/nexa_spec.rb +57 -0
  121. data/spec/tellstick/protocol/proove_spec.rb +61 -0
  122. data/spec/tellstick/protocol/rising_sun_spec.rb +56 -0
  123. data/spec/tellstick/protocol/waveman_spec.rb +57 -0
  124. data/spec/tellstick/tellstick_io_spec.rb +31 -0
  125. data/spec/tellstick/tellstick_spec.rb +86 -0
  126. data/spec/trigger_switch_d/application_spec.rb +144 -0
  127. data/spec/trigger_switch_d/config_spec.rb +94 -0
  128. data/spec/trigger_switch_d/daylight_spec.rb +39 -0
  129. data/spec/trigger_switch_d/ipc_spec.rb +119 -0
  130. data/spec/trigger_switch_d/schedule_spec.rb +103 -0
  131. data/spec/trigger_switch_d/trigger_switch_d_spec_helpers.rb +24 -0
  132. data/trigger_switch_d.gemspec +43 -0
  133. metadata +206 -0
@@ -0,0 +1,80 @@
1
+ # TriggerSwitchD, executes commands to activate/deactive remote switches.
2
+ # (c) Copyright 2010 Pontus Strömdahl, AdhocSkill.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+
18
+ require "rubygems"
19
+ require "ftd2xx"
20
+ require "pp"
21
+
22
+ module Tellstick
23
+
24
+ #IO stream associated with the tellstick
25
+ class TellstickIO
26
+ def initialize
27
+ open
28
+ end
29
+
30
+ #writes input string to tellstick
31
+ def puts(input)
32
+ input.scan(/.{1,8}/).each do |str|
33
+ Ftd2xx.write(@handle,str)
34
+ end
35
+ end
36
+
37
+ #reads string from tellstick
38
+ def gets
39
+ reply = ""
40
+ bytes_read = 1
41
+ c = " "
42
+ while (bytes_read != 0) and (c != "\n")
43
+ c = " "
44
+ bytes_read = Ftd2xx.read(@handle,c)
45
+ reply << c
46
+ end
47
+ reply
48
+ end
49
+
50
+ #close tellstick stream
51
+ def close
52
+ Ftd2xx.ft_close(@handle)
53
+ @handle = nil
54
+ end
55
+
56
+ #opens tellstick stream
57
+ def open
58
+ Ftd2xx.ft_set_vidpid(0x1781,0x0c30)
59
+ device_index = Ftd2xx.create_device_info_list - 1
60
+ @handle = Ftd2xx.open(device_index)
61
+ Ftd2xx.ft_set_baud_rate(@handle,4800)
62
+ Ftd2xx.ft_set_timeouts(@handle,5000,0)
63
+ if @handle == nil
64
+ def puts(input);end
65
+ def gets;end
66
+ end
67
+ end
68
+
69
+ #true if connected
70
+ def connected?
71
+ close
72
+ open
73
+ puts("S+")
74
+ answer = gets
75
+ close
76
+ open
77
+ answer == "+S\r\n"
78
+ end
79
+ end
80
+ end
data/lib/tellstick.rb ADDED
@@ -0,0 +1,20 @@
1
+ # TriggerSwitchD, executes commands to activate/deactive remote switches.
2
+ # (c) Copyright 2010 Pontus Strömdahl, AdhocSkill.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+
18
+ require "tellstick/tellstick"
19
+ require "tellstick/tellstick_io"
20
+
@@ -0,0 +1,83 @@
1
+ # TriggerSwitchD, executes commands to activate/deactive remote switches.
2
+ # (c) Copyright 2010 Pontus Strömdahl, AdhocSkill.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+
18
+ require File.join(File.dirname(__FILE__),"trigger_switch_d_helper")
19
+
20
+ module TriggerSwitchD
21
+ #Uses the ruby engine to transform code_line into method execute on an instance of Action
22
+ class Action
23
+
24
+ #Takes a code_line to be scheduled or executed together with the devices, environment
25
+ #and date to validate it.
26
+ def initialize(code_line,devices,environment=Config.default_environment,date=Date.today)
27
+ @name = code_line.strip
28
+ @date = date
29
+ @at_location = environment[:at_location]
30
+ @lookup = environment[:lookup]
31
+ tokens = code_line.scan(/(\w+) (\w+) (\w+) ([\w\d:]+)/u).flatten
32
+ (class << self;self;end).methodize_device(tokens[1],devices[tokens[1]],@lookup) if devices.include? tokens[1]
33
+ code = tokens.map do |token|
34
+ (@lookup.include? token) ? @lookup[token] : token
35
+ end.reverse
36
+ @at, executable = send(code[3], send(code[2], send(code[1], code[0])))
37
+ (class << self;self;end).methodize_executable(executable)
38
+ end
39
+
40
+ def activate(*args) #:nodoc:
41
+ action(args[0][0],args[0][1],:turn_on)
42
+ end
43
+
44
+ def deactivate(*args) #:nodoc:
45
+ action(args[0][0],args[0][1],:turn_off)
46
+ end
47
+
48
+ def at(*args) #:nodoc:
49
+ return @at if args[0] == nil
50
+ if (args[0] =~ /(?:2[0-3]|[01]\d):[0-5]\d/) == 0
51
+ return args[0]
52
+ end
53
+ return @date.extend(Daylight).send(args[0],@at_location).localtime.strftime("%H:%M")
54
+ end
55
+
56
+ def to_s
57
+ @name
58
+ end
59
+
60
+ private
61
+
62
+ def action(*args)
63
+ switches, at_time, event = args
64
+ code = Proc.new do |output|
65
+ switches.each do |switch|
66
+ Tellstick::create(output,switch.model_name).send(event,switch.house_code, switch.unit_code)
67
+ end
68
+ end
69
+ [at_time,code]
70
+ end
71
+
72
+ def self.methodize_executable(executable)
73
+ define_method(:execute,&executable)
74
+ end
75
+
76
+ def self.methodize_device(name,switches,lookup)
77
+ lookup[name] = :remote_device.to_s
78
+ define_method(:remote_device) do |*args|
79
+ [switches,args[0]]
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,89 @@
1
+ # TriggerSwitchD, executes commands to activate/deactive remote switches.
2
+ # (c) Copyright 2010 Pontus Strömdahl, AdhocSkill.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require 'socket'
18
+ require 'yaml'
19
+ require 'logger'
20
+ require 'ipc'
21
+
22
+
23
+ module TriggerSwitchD
24
+
25
+ #starts an instance of the daemon.
26
+ class Application
27
+ attr_reader :devices, :schedule, :logger
28
+ alias_method :list_devices, :devices
29
+
30
+ #Prepares the run by loading up the environment
31
+ #located in config/config.rb
32
+ def initialize(config_file)
33
+ @current_date = Date.new
34
+ ConfigFactory.new(config_file)
35
+ @logger = Logger.new(Config.log_object)
36
+ logger.info("Environment prepared")
37
+ end
38
+
39
+ #Runs the daemon untill process killed or it receives
40
+ #stop from client connected via unix socket
41
+ def start
42
+ com_thread = IPC.create(Config.unix_socket_path)
43
+ logger.info("IPC started")
44
+ com_thread["received"] = "anything"
45
+ while ((command = com_thread["received"].to_sym) != :stop)
46
+ now_time = Time.new
47
+ load_db(now_time.strftime("%Y-%m-%d %H:%M:%S"))
48
+ hhmm_now_time = now_time.strftime("%H:%M")
49
+ if methods.include? command.to_s
50
+ com_thread["response"] = send(command).to_yaml
51
+ logger.info("Received #{command} via IPC")
52
+ Config.log_object.flush
53
+ com_thread["received"] = "anything"
54
+ com_thread.run
55
+ end
56
+ if (schedule.cronological.keys.include? hhmm_now_time)
57
+ logger.info("Executed #{schedule.cronological[hhmm_now_time].length} action(s) at #{hhmm_now_time}")
58
+ Config.log_object.flush
59
+ schedule.execute(hhmm_now_time,Config.output)
60
+ end
61
+ Kernel.sleep(1)
62
+ com_thread["received"] = "anything" if com_thread["received"] == ""
63
+ end
64
+ logger.info("Received #{command} via IPC")
65
+ end
66
+
67
+ def list_schedule #:nodoc:
68
+ schedule.by_name.keys
69
+ end
70
+
71
+ private
72
+
73
+ def load_db(time)
74
+ date = Date.parse(time)
75
+ return unless @current_date < date
76
+ file = File.open(Config.db_path[0],"r")
77
+ @devices = TriggerSwitchD::load_devices(file)
78
+ file.close
79
+ @schedule = Schedule.create
80
+ file = File.open(Config.db_path[1],"r")
81
+ TriggerSwitchD::load_scheduled_actions(file,@schedule,devices,Config.environment)
82
+ file.close
83
+ logger.info("Loaded #{devices.length} devices and #{schedule.by_name.length} actions")
84
+ Config.log_object.flush
85
+ @current_date = date
86
+ end
87
+
88
+ end
89
+ end
@@ -0,0 +1,83 @@
1
+ # TriggerSwitchD, executes commands to activate/deactive remote switches.
2
+ # (c) Copyright 2010 Pontus Strömdahl, AdhocSkill.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+
18
+ module TriggerSwitchD
19
+ module ConfigFactory
20
+
21
+ #Creates the Config class from the config/config.rb file
22
+ #See samples/config.rb for more documentation
23
+ def self.new(file=StringIO.new)
24
+ env = file.readlines
25
+ attributes = env.map do |attribute|
26
+ attribute.scan(/Config.([\w_]+) =/).flatten[0]
27
+ end
28
+ cls = <<-EOS
29
+ class Config
30
+ #{attributes.map {|name| "def self.#{name}=(value); #{append_filenames(name)}; end"}.join("\n")}
31
+
32
+ #{attributes.map {|name| "def self.#{name}; @#{name}; end"}.join("\n")}
33
+
34
+ def self.default_environment
35
+ {:lookup => {"tänd" => "activate",
36
+ "släck" => "deactivate",
37
+ "soluppgång" => "sunrise",
38
+ "solnedgång" => "sunset",
39
+ "klockan" => "at",
40
+ "vid" => "at"},
41
+ :at_location => {:north => 0.0, :west => 0.0}}
42
+ end
43
+ end
44
+ EOS
45
+ ::TriggerSwitchD.module_eval(cls)
46
+ setup_environment(env)
47
+ end
48
+
49
+ private
50
+ def self.setup_environment(env)
51
+ env.map do |attribute|
52
+ ::TriggerSwitchD.module_eval(attribute)
53
+ end
54
+ def Config.environment
55
+ result = default_environment
56
+ file = File.open(Config.dsl_path,"r")
57
+ result[:lookup] = YAML::load(file)
58
+ file.close
59
+ result[:at_location] = Config.geo_position
60
+ result
61
+ end
62
+ end
63
+
64
+ def self.set_type(name)
65
+ types = {"log_object" => "{:spec => StringIO.new, :development => STDOUT, :file => File.open(\"#log_path}\",\"a+\")}",
66
+ "output" => "{:spec => StringIO.new, :development => STDOUT, :tellstick => Tellstick::TellstickIO.new}"}
67
+ return "@#{name}=value" unless types.keys.include? name
68
+ "@#{name}=#{types[name]}[value]".gsub("log_path","{log_path")
69
+ end
70
+
71
+ def self.append_filenames(name)
72
+ filenames = {"log_path" => ["tsd.log"], "db_path" => ["devices","scheduled_actions"],
73
+ "dsl_path" => ["lookup.dsl"], "unix_socket_path" => ["com.adhocskill.trigger_switch_d"]}
74
+ return set_type(name) unless filenames.keys.include? name
75
+ result = filenames[name].map do |fname|
76
+ "#value}/#{fname}"
77
+ end.inspect.gsub("value","{value")
78
+ result = result.gsub("[","").gsub("]","") if filenames[name].length == 1
79
+ "@#{name}=#{result}"
80
+ end
81
+ end
82
+ end
83
+
@@ -0,0 +1,114 @@
1
+ # TriggerSwitchD, executes commands to activate/deactive remote switches.
2
+ # (c) Copyright 2010 Pontus Strömdahl, AdhocSkill.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+
18
+ # External referenses used:
19
+ # http://www.stjarnhimlen.se (accessed 2010-03-02)
20
+ # http://users.electromagnetic.net/bu/astro/sunrise-set.php (accessed 2010-03-02)
21
+ # http://www.astro.uu.nl/~strous/AA/en/reken/zonpositie.html (accessed 2010-03-02)
22
+
23
+ module Daylight #:nodoc:all
24
+
25
+ JULIAN_DAYS_UNTIL_YEAR_2000 = 2451545.0
26
+ UNIT_CIRCLE = 360.0
27
+ C1 = 0.0009
28
+ C2 = 357.5291
29
+ C3 = 0.98560028
30
+ C4 = 1.9148
31
+ C5 = 0.0200
32
+ C6 = 0.0003
33
+ C7 = 102.9372
34
+ C8 = 0.0053
35
+ C9 = 0.0069
36
+ C10 = 23.45
37
+ C11 = -0.83
38
+ FOR = {:sunrise => -1, :sunset => 1}
39
+
40
+ def self.extended(receiver)
41
+ days = receiver.jd
42
+ raise "method jd on #{receiver} does not return Fixnum" unless days.kind_of? Fixnum
43
+ end
44
+
45
+ def sunrise(at_location)
46
+ time_for(:sunrise,at_location)
47
+ end
48
+
49
+ def sunset(at_location)
50
+ time_for(:sunset,at_location)
51
+ end
52
+
53
+ private
54
+
55
+ def time_for(what_time,at_location)
56
+ __prepare_float__
57
+ n = ((days_since_2000 - C1) - per_unit_circle(at_location[:west])).round
58
+ j = JULIAN_DAYS_UNTIL_YEAR_2000 + C1 + (per_unit_circle(at_location[:west])) + n
59
+
60
+ transit_approx = stable_transit_approximation(j)
61
+
62
+ declination = Math.asin(Math.sin(transit_approx[:lamda].to_rad) * Math.sin(C10.to_rad)).to_degrees
63
+ h = (Math.acos((Math.sin(C11.to_rad) - Math.sin(at_location[:north].to_rad)*Math.sin(declination.to_rad))/(Math.cos(at_location[:north].to_rad) * Math.cos(declination.to_rad)))).to_degrees
64
+ j2 = JULIAN_DAYS_UNTIL_YEAR_2000 + C1 + per_unit_circle(FOR[what_time]*h + at_location[:west]) + n
65
+ raw = j2 + (C8 * Math.sin(transit_approx[:m].to_rad)) - (C9 * Math.sin(2*transit_approx[:lamda].to_rad))
66
+ dt = DateTime.jd(raw).new_offset(0.5)
67
+ Time.utc(dt.year,dt.month,dt.day,dt.hour,dt.min,dt.sec,0)
68
+ end
69
+
70
+ def stable_transit_approximation(j)
71
+ transit_approx = transit_approximation(j,j)
72
+ count = 5
73
+ until((transit_approx == (transit_approx = transit_approximation(j,transit_approx[:transit]))) || count <= 0)
74
+ count -= 1
75
+ end
76
+ transit_approx
77
+ end
78
+
79
+ def transit_approximation(j,transit)
80
+ m = mod_unit_circle(C2 + C3 * (transit - JULIAN_DAYS_UNTIL_YEAR_2000))
81
+ c = (C4 * Math.sin(m.to_rad)) + (C5 * Math.sin(2 * m.to_rad)) + (C6 * Math.sin(3 * m.to_rad))
82
+ lamda = mod_unit_circle(m + C7 + c + UNIT_CIRCLE/2)
83
+ transit = j + (C8 * Math.sin(m.to_rad)) - (C9 * Math.sin(2 * lamda.to_rad))
84
+ {:m => m, :lamda => lamda, :transit => transit}
85
+ end
86
+
87
+ def days_since_2000
88
+ self.jd - JULIAN_DAYS_UNTIL_YEAR_2000
89
+ end
90
+
91
+ def per_unit_circle(value)
92
+ value / UNIT_CIRCLE
93
+ end
94
+
95
+ def mod_unit_circle(value)
96
+ value % UNIT_CIRCLE
97
+ end
98
+
99
+ def __prepare_float__
100
+ Float.class_eval {include DayFloat}
101
+ def __prepare_float__
102
+ end
103
+ end
104
+
105
+ module DayFloat
106
+ def to_rad
107
+ self * Math::PI/180.0
108
+ end
109
+ def to_degrees
110
+ self * 180.0/Math::PI
111
+ end
112
+ end
113
+
114
+ end
@@ -0,0 +1,39 @@
1
+ # TriggerSwitchD, executes commands to activate/deactive remote switches.
2
+ # (c) Copyright 2010 Pontus Strömdahl, AdhocSkill.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ module TriggerSwitchD
18
+ module IPC
19
+
20
+ #unix socket thread, see README.rdoc for usage
21
+ def self.create(socket_path)
22
+ File.delete(socket_path) if File.exist? socket_path
23
+ sock = UNIXServer.open(socket_path)
24
+ Thread.start(sock) do |sock|
25
+ while(!["stop"].include?(Thread.current["received"]))
26
+ Thread.current["received"] = ""
27
+ s1 = sock.accept
28
+ while(!["stop","bye"].include?(Thread.current["received"]))
29
+ Thread.current["received"] = s1.recvfrom(200)[0]
30
+ Thread.current["response"] = Thread.current["received"] if Thread.current["received"] == "bye"
31
+ Thread.stop if !["bye",""].include?(Thread.current["received"])
32
+ s1.send(Thread.current["response"],0) unless Thread.current["received"] == ""
33
+ Thread.current["received"] = "bye" if Thread.current["received"] == ""
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,95 @@
1
+ # TriggerSwitchD, executes commands to activate/deactive remote switches.
2
+ # (c) Copyright 2010 Pontus Strömdahl, AdhocSkill.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+
18
+ require File.join(File.dirname(__FILE__),"trigger_switch_d_helper")
19
+ require File.join(File.dirname(__FILE__),"action")
20
+
21
+ module TriggerSwitchD
22
+ #Holds actions organized by name and cronological
23
+ #Use create to instasiate
24
+ module Schedule
25
+ module InstanceMethods
26
+ def schedule_action(action)
27
+ self._insert_action_(action) if find(action.to_s) == nil
28
+ find(action.to_s)
29
+ end
30
+
31
+ #find by name
32
+ def find(name)
33
+ by_name[name]
34
+ end
35
+
36
+ #Returns when the next action is scheduled to occur
37
+ #based on the hour_minute. The format is "HH:MM" for both
38
+ #hour_minute as well as the result, with the exception
39
+ #that if no next action is found it will return
40
+ #"23:59:59"
41
+ def next_action_at(hour_minute)
42
+ end_of_day = "23:59:59"
43
+ return end_of_day unless hour_minute =~ /\d{2}:\d{2}/
44
+ time = Time.parse(hour_minute)
45
+ cronological.keys.sort {|x,y| Time.parse(x) <=> Time.parse(y)}.find(Proc.new {end_of_day}) do |at|
46
+ time < Time.parse(at)
47
+ end
48
+ end
49
+
50
+ #deletes action from schedule, returning the action on exit
51
+ def delete(name)
52
+ action = by_name.delete(name)
53
+ cronological[action.at].delete(name)
54
+ end
55
+
56
+ #Executes action and removes it from the schedule
57
+ def execute(at,output)
58
+ cronological[at].values.each { |action| action.execute(output) } unless cronological[at] == nil
59
+ self._remove_executed_actions_from_schedule_(at)
60
+ end
61
+
62
+ #Hash of actions accessible by "HH:MM" format
63
+ def cronological
64
+ self[:cronological]
65
+ end
66
+
67
+ #Hash of actions accessible by name
68
+ def by_name
69
+ self[:all]
70
+ end
71
+
72
+ def _remove_executed_actions_from_schedule_(at) #:nodoc:
73
+ cronological[at].values.clone.each do |element|
74
+ by_name.delete(element.to_s)
75
+ end unless cronological[at] == nil
76
+ cronological.delete(at)
77
+ end
78
+
79
+ def _insert_action_(action) #:nodoc:
80
+ name = action.to_s
81
+ by_name[name] = action
82
+ cronological[action.at] ||= {}
83
+ cronological[action.at][name] = by_name[name]
84
+ end
85
+ end
86
+
87
+ #Creates an instance of a schedule
88
+ def create
89
+ schedule = {:all => {}, :cronological => {}}
90
+ schedule.extend InstanceMethods
91
+ end
92
+
93
+ module_function :create
94
+ end
95
+ end
@@ -0,0 +1,37 @@
1
+ # TriggerSwitchD, executes commands to activate/deactive remote switches.
2
+ # (c) Copyright 2010 Pontus Strömdahl, AdhocSkill.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+
18
+ module TriggerSwitchD
19
+ module SwitchFactory
20
+ #Creates the Switch class dynamically from values, which is
21
+ #assumed to be an Array of attributes/keys
22
+ def self.new(values)
23
+ definition = <<-EOS
24
+ class Switch
25
+ attr_reader #{values.map {|name| ":#{name}"}.join(",")}
26
+ def initialize(value)
27
+ value.each_pair do |key,value|
28
+ instance_variable_set("@"+key.to_s,value) if respond_to?(key)
29
+ end
30
+ end
31
+ end
32
+ EOS
33
+ ::TriggerSwitchD.module_eval(definition)
34
+ ::TriggerSwitchD.const_get("Switch")
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,44 @@
1
+ # TriggerSwitchD, executes commands to activate/deactive remote switches.
2
+ # (c) Copyright 2010 Pontus Strömdahl, AdhocSkill.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+
18
+ module TriggerSwitchD
19
+
20
+ #Loads up schedule with the actions in file
21
+ def load_scheduled_actions(file,schedule,devices,environment,date=Date.today)
22
+ rows = file.readlines
23
+ rows.each do |code_line|
24
+ action = Action.new(code_line,devices,environment,date)
25
+ schedule.schedule_action(action) #unless Time.parse(action.at) < Time.now
26
+ end
27
+ end
28
+
29
+ #Returns devices loaded from file
30
+ def load_devices(file)
31
+ devices = YAML::load(file)
32
+ SwitchFactory.new(devices[0]["switches"][0].keys)
33
+ result = {}
34
+ devices.each do |device|
35
+ switches = device["switches"].map do |switch|
36
+ TriggerSwitchD::Switch.new(switch)
37
+ end
38
+ result[device["name"]] = switches
39
+ end
40
+ result
41
+ end
42
+
43
+ module_function :load_scheduled_actions, :load_devices
44
+ end