meac_control 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +13 -0
- data/README.md +35 -0
- data/Rakefile +50 -0
- data/VERSION.yml +5 -0
- data/lib/meac_control.rb +4 -0
- data/lib/meac_control/command.rb +4 -0
- data/lib/meac_control/command/drive.rb +20 -0
- data/lib/meac_control/command/fan_speed.rb +32 -0
- data/lib/meac_control/command/generic.rb +32 -0
- data/lib/meac_control/command/inlet_temp.rb +11 -0
- data/lib/meac_control/device.rb +11 -0
- data/lib/meac_control/http.rb +42 -0
- data/lib/meac_control/xml.rb +5 -0
- data/lib/meac_control/xml/abstract_request.rb +36 -0
- data/lib/meac_control/xml/exceptions.rb +14 -0
- data/lib/meac_control/xml/get_request.rb +16 -0
- data/lib/meac_control/xml/response.rb +44 -0
- data/lib/meac_control/xml/set_request.rb +16 -0
- data/spec/fixtures/get-request.xml +7 -0
- data/spec/fixtures/get-response-error.xml +8 -0
- data/spec/fixtures/get-response-ok.xml +7 -0
- data/spec/fixtures/set-request.xml +7 -0
- data/spec/lib/meac_control/command/drive_spec.rb +28 -0
- data/spec/lib/meac_control/command/fan_speed_spec.rb +23 -0
- data/spec/lib/meac_control/command/generic_spec.rb +86 -0
- data/spec/lib/meac_control/command/inlet_temp_spec.rb +14 -0
- data/spec/lib/meac_control/device_spec.rb +23 -0
- data/spec/lib/meac_control/http_spec.rb +76 -0
- data/spec/lib/meac_control/xml/abstract_request_spec.rb +141 -0
- data/spec/lib/meac_control/xml/get_request_spec.rb +26 -0
- data/spec/lib/meac_control/xml/response_spec.rb +76 -0
- data/spec/lib/meac_control/xml/set_request_spec.rb +26 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/support/shared_examples.rb +5 -0
- metadata +130 -0
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2010 Bernd Ahlers <bernd@tuneafish.de>
|
2
|
+
|
3
|
+
Permission to use, copy, modify, and distribute this software for any
|
4
|
+
purpose with or without fee is hereby granted, provided that the above
|
5
|
+
copyright notice and this permission notice appear in all copies.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
## MEACControl
|
2
|
+
|
3
|
+
The library provides some Ruby classes to interact with a Mitsubishi Electric
|
4
|
+
G-50A centralized controller. This device is used to control up to 50 indoor
|
5
|
+
air conditioning units.
|
6
|
+
|
7
|
+
The G-50A offers a XML API for the communication.
|
8
|
+
|
9
|
+
So far, the library has only been tested with a G-50A. I'm not sure if there
|
10
|
+
are other controller/devices which use the same API.
|
11
|
+
|
12
|
+
### Security
|
13
|
+
|
14
|
+
Mitsubishi recommends to put the controller into a private network. In fact,
|
15
|
+
there's no authentication or encryption needed to access the controller.
|
16
|
+
There's been a post to the BugTraq mailing list in March 2008 regarding that.
|
17
|
+
[Archive](http://www.securityfocus.com/archive/1/489970)
|
18
|
+
|
19
|
+
### Code Examples
|
20
|
+
|
21
|
+
Please see the `example` directory for code examples.
|
22
|
+
|
23
|
+
### Note on Patches/Pull Requests
|
24
|
+
|
25
|
+
* Fork the project.
|
26
|
+
* Write a spec to cover a bug or a new feature.
|
27
|
+
* Make your feature addition or bug fix.
|
28
|
+
* Commit, do not mess with rakefile, version, or history.
|
29
|
+
(if you want to have your own version, that is fine but bump version in a
|
30
|
+
commit by itself I can ignore when I pull)
|
31
|
+
* Send me a pull request. Bonus points for topic branches.
|
32
|
+
|
33
|
+
### Copyright
|
34
|
+
|
35
|
+
Copyright (c) 2010 Bernd Ahlers. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "meac_control"
|
8
|
+
gem.summary = %Q{Library to communicate with a Mitsubishi Electric G-50A centralized controller}
|
9
|
+
gem.description = %Q{Library to communicate with a Mitsubishi Electric G-50A centralized controller}
|
10
|
+
gem.email = "bernd@tuneafish.de"
|
11
|
+
gem.homepage = "http://github.com/bernd/meac_control"
|
12
|
+
gem.authors = ["Bernd Ahlers"]
|
13
|
+
|
14
|
+
gem.files = FileList["LICENSE", "README.md", "Rakefile", "VERSION.yml", "{lib,spec}/**/*"]
|
15
|
+
|
16
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
17
|
+
|
18
|
+
gem.add_dependency "httpclient"
|
19
|
+
gem.add_dependency "nokogiri"
|
20
|
+
end
|
21
|
+
Jeweler::GemcutterTasks.new
|
22
|
+
rescue LoadError
|
23
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'spec/rake/spectask'
|
27
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
30
|
+
end
|
31
|
+
|
32
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
33
|
+
spec.libs << 'lib' << 'spec'
|
34
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
35
|
+
spec.rcov = true
|
36
|
+
end
|
37
|
+
|
38
|
+
task :spec => :check_dependencies
|
39
|
+
|
40
|
+
task :default => :spec
|
41
|
+
|
42
|
+
require 'rake/rdoctask'
|
43
|
+
Rake::RDocTask.new do |rdoc|
|
44
|
+
version = Jeweler::VersionHelper.new(File.dirname(__FILE__))
|
45
|
+
|
46
|
+
rdoc.rdoc_dir = 'rdoc'
|
47
|
+
rdoc.title = "MEACControl #{version}"
|
48
|
+
rdoc.rdoc_files.include('README*')
|
49
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
50
|
+
end
|
data/VERSION.yml
ADDED
data/lib/meac_control.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'meac_control/command/generic'
|
2
|
+
|
3
|
+
module MEACControl
|
4
|
+
module Command
|
5
|
+
class Drive < Generic
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@command = 'Drive'
|
9
|
+
end
|
10
|
+
|
11
|
+
def on
|
12
|
+
@value = 'ON'
|
13
|
+
end
|
14
|
+
|
15
|
+
def off
|
16
|
+
@value = 'OFF'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'meac_control/command/generic'
|
2
|
+
|
3
|
+
module MEACControl
|
4
|
+
module Command
|
5
|
+
class FanSpeed < Generic
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@command = 'FanSpeed'
|
9
|
+
end
|
10
|
+
|
11
|
+
def low
|
12
|
+
@value = 'low'
|
13
|
+
end
|
14
|
+
|
15
|
+
def mid1
|
16
|
+
@value = 'mid1'
|
17
|
+
end
|
18
|
+
|
19
|
+
def mid2
|
20
|
+
@value = 'mid2'
|
21
|
+
end
|
22
|
+
|
23
|
+
def high
|
24
|
+
@value = 'high'
|
25
|
+
end
|
26
|
+
|
27
|
+
def auto
|
28
|
+
@value = 'auto'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module MEACControl
|
2
|
+
module Command
|
3
|
+
class InvalidValue < Exception
|
4
|
+
end
|
5
|
+
|
6
|
+
class InvalidMode < Exception
|
7
|
+
end
|
8
|
+
|
9
|
+
class Generic
|
10
|
+
attr_reader :command, :value
|
11
|
+
|
12
|
+
def self.request
|
13
|
+
new.freeze
|
14
|
+
end
|
15
|
+
|
16
|
+
def hash_for(mode)
|
17
|
+
if mode == :set
|
18
|
+
raise MEACControl::Command::InvalidValue if (value.nil? or value.empty?)
|
19
|
+
{command.to_sym => value}
|
20
|
+
elsif mode == :get
|
21
|
+
{command.to_sym => '*'}
|
22
|
+
else
|
23
|
+
raise MEACControl::Command::InvalidMode
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def command_set?
|
28
|
+
(value.nil? or value.empty?) ? false : true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'meac_control/xml/get_request'
|
2
|
+
require 'meac_control/xml/set_request'
|
3
|
+
require 'meac_control/xml/response'
|
4
|
+
require 'httpclient'
|
5
|
+
|
6
|
+
module MEACControl
|
7
|
+
class HTTP
|
8
|
+
URI_TEMPLATE = 'http://%s/servlet/MIMEReceiveServlet'
|
9
|
+
DEFAULT_HEADER = {'Accept' => 'text/xml', 'Content-Type' => 'text/xml'}
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# Executes a get request and returns a MEACControl::XML::Response object.
|
13
|
+
#
|
14
|
+
# Example:
|
15
|
+
# device = MEACControl::Device.new(23)
|
16
|
+
# command = MEACControl::Command::Drive.request
|
17
|
+
# resp = MEACControl::HTTP.get('127.0.0.1', device, command)
|
18
|
+
# resp.inspect # => "#<MEACControl::XML::Response:0x8bea3ef0 ...>"
|
19
|
+
def get(host, devices, commands)
|
20
|
+
action(host, MEACControl::XML::GetRequest.new(devices, commands))
|
21
|
+
end
|
22
|
+
|
23
|
+
# Executes a set request and returns a MEACControl::XML::Response object.
|
24
|
+
#
|
25
|
+
# Example:
|
26
|
+
# device = MEACControl::Device.new(23)
|
27
|
+
# command = MEACControl::Command::Drive.new
|
28
|
+
# command.off
|
29
|
+
# resp = MEACControl::HTTP.set('127.0.0.1', device, command)
|
30
|
+
# resp.inspect # => "#<MEACControl::XML::Response:0x8bea3ef0 ...>"
|
31
|
+
def set(host, devices, commands)
|
32
|
+
action(host, MEACControl::XML::SetRequest.new(devices, commands))
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def action(host, request)
|
37
|
+
resp = HTTPClient.post(sprintf(URI_TEMPLATE, host), request.to_xml, DEFAULT_HEADER)
|
38
|
+
MEACControl::XML::Response.new(resp.content, request)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'meac_control/xml/exceptions'
|
3
|
+
|
4
|
+
module MEACControl
|
5
|
+
module XML
|
6
|
+
class AbstractRequest
|
7
|
+
attr_reader :devices, :commands
|
8
|
+
|
9
|
+
def initialize(devices, commands)
|
10
|
+
@devices = [devices].compact.flatten
|
11
|
+
@commands = [commands].compact.flatten
|
12
|
+
|
13
|
+
raise MEACControl::XML::Request::EmptyDeviceList if @devices.empty?
|
14
|
+
raise MEACControl::XML::Request::EmptyCommandList if @commands.empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def xml_template(command, mode)
|
19
|
+
::Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do
|
20
|
+
Packet do
|
21
|
+
Command command
|
22
|
+
DatabaseManager do
|
23
|
+
devices.each do |dev|
|
24
|
+
attributes = {:Group => dev.id}
|
25
|
+
commands.each do |cmd|
|
26
|
+
attributes.merge!(cmd.hash_for(mode))
|
27
|
+
end
|
28
|
+
Mnet(attributes)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end.to_xml
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'meac_control/xml/abstract_request'
|
2
|
+
|
3
|
+
module MEACControl
|
4
|
+
module XML
|
5
|
+
class GetRequest < AbstractRequest
|
6
|
+
# returns a xml get request.
|
7
|
+
#
|
8
|
+
# example:
|
9
|
+
# req = MEACControl::XML::GetRequest.new(device, command)
|
10
|
+
# req.to_xml # => "<?xml version="1.0" encoding="UTF-8"?>..."
|
11
|
+
def to_xml
|
12
|
+
xml_template('getRequest', :get)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'meac_control/xml/exceptions'
|
3
|
+
|
4
|
+
module MEACControl
|
5
|
+
module XML
|
6
|
+
class Response
|
7
|
+
attr_reader :xml, :request
|
8
|
+
|
9
|
+
def initialize(xml, request = nil)
|
10
|
+
@xml = ::Nokogiri::XML(xml)
|
11
|
+
@request = request
|
12
|
+
raise(MEACControl::XML::InvalidResponse, @xml.to_s) if @xml.root.nil?
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_xml
|
16
|
+
@xml.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
def ok?
|
20
|
+
!errors?
|
21
|
+
end
|
22
|
+
|
23
|
+
def errors?
|
24
|
+
!@xml.xpath('/Packet/DatabaseManager/ERROR').empty?
|
25
|
+
end
|
26
|
+
|
27
|
+
def errors
|
28
|
+
@xml.xpath('/Packet/DatabaseManager/ERROR').map do |error|
|
29
|
+
data = {}
|
30
|
+
error.each do |key, value|
|
31
|
+
data[key] = value
|
32
|
+
end
|
33
|
+
data
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def error_messages
|
38
|
+
errors.map do |error|
|
39
|
+
error['Message']
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'meac_control/xml/abstract_request'
|
2
|
+
|
3
|
+
module MEACControl
|
4
|
+
module XML
|
5
|
+
class SetRequest < AbstractRequest
|
6
|
+
# returns a xml set request.
|
7
|
+
#
|
8
|
+
# example:
|
9
|
+
# req = MEACControl::XML::SetRequest.new(device, command)
|
10
|
+
# req.to_xml # => "<?xml version="1.0" encoding="UTF-8"?>..."
|
11
|
+
def to_xml
|
12
|
+
xml_template('setRequest', :set)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper'))
|
2
|
+
require 'meac_control/command/drive'
|
3
|
+
|
4
|
+
describe MEACControl::Command::Drive do
|
5
|
+
before(:each) do
|
6
|
+
@cmd = MEACControl::Command::Drive.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it_should_behave_like "a class that includes MEACControl::Command::Generic"
|
10
|
+
|
11
|
+
it "has set the command to 'Drive'" do
|
12
|
+
@cmd.command.should == 'Drive'
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#on" do
|
16
|
+
it "sets the value to 'ON'" do
|
17
|
+
@cmd.on
|
18
|
+
@cmd.value.should == 'ON'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#off" do
|
23
|
+
it "sets the value to 'OFF'" do
|
24
|
+
@cmd.off
|
25
|
+
@cmd.value.should == 'OFF'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper'))
|
2
|
+
require 'meac_control/command/fan_speed'
|
3
|
+
|
4
|
+
describe MEACControl::Command::FanSpeed do
|
5
|
+
before(:each) do
|
6
|
+
@cmd = MEACControl::Command::FanSpeed.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it_should_behave_like "a class that includes MEACControl::Command::Generic"
|
10
|
+
|
11
|
+
it "has set the command to 'FanSpeed'" do
|
12
|
+
@cmd.command.should == 'FanSpeed'
|
13
|
+
end
|
14
|
+
|
15
|
+
%w{low mid1 mid2 high auto}.each do |c|
|
16
|
+
describe "##{c}" do
|
17
|
+
it "sets the value to '#{c}'" do
|
18
|
+
@cmd.send(c)
|
19
|
+
@cmd.value.should == c
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper'))
|
2
|
+
require 'meac_control/command/generic'
|
3
|
+
|
4
|
+
class Cmd < MEACControl::Command::Generic
|
5
|
+
def initialize
|
6
|
+
@command = "MyCommand"
|
7
|
+
@value = "MyValue"
|
8
|
+
end
|
9
|
+
|
10
|
+
def on
|
11
|
+
@value = 'ON'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe MEACControl::Command::Generic do
|
16
|
+
before(:each) do
|
17
|
+
@obj = Cmd.new
|
18
|
+
end
|
19
|
+
|
20
|
+
describe ".request" do
|
21
|
+
it "returns a new frozen object" do
|
22
|
+
Cmd.request.should be_frozen
|
23
|
+
end
|
24
|
+
|
25
|
+
it "does not allow modifications" do
|
26
|
+
lambda { Cmd.request.on }.should raise_error(TypeError)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#hash_for" do
|
31
|
+
it "will raise an exception if it's called without argument" do
|
32
|
+
lambda { @obj.hash_for }.should raise_error(ArgumentError)
|
33
|
+
end
|
34
|
+
|
35
|
+
context "with the :get argument" do
|
36
|
+
it "returns a hash with the command name as key and a value of '*'" do
|
37
|
+
@obj.hash_for(:get).should == {@obj.command.to_sym => '*'}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "with the :set argument" do
|
42
|
+
it "returns a hash with the command as key and the command value as value" do
|
43
|
+
@obj.hash_for(:set).should == {@obj.command.to_sym => @obj.value}
|
44
|
+
end
|
45
|
+
|
46
|
+
it "will raise an exception if value is nil" do
|
47
|
+
@obj.stub!(:value).and_return(nil)
|
48
|
+
lambda { @obj.hash_for(:set) }.should raise_error(MEACControl::Command::InvalidValue)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "will raise an exception if value is an empty string" do
|
52
|
+
@obj.stub!(:value).and_return('')
|
53
|
+
lambda { @obj.hash_for(:set) }.should raise_error(MEACControl::Command::InvalidValue)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "with an unknown argument" do
|
58
|
+
it "will raise an exception" do
|
59
|
+
lambda { @obj.hash_for(:foobar_unknown) }.should raise_error(MEACControl::Command::InvalidMode)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#command_set?" do
|
65
|
+
context "with value set to 'YES'" do
|
66
|
+
it "returns true" do
|
67
|
+
@obj.stub!(:value).and_return('YES')
|
68
|
+
@obj.command_set?.should be_true
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "with value set to an empty string" do
|
73
|
+
it "returns false" do
|
74
|
+
@obj.stub!(:value).and_return('')
|
75
|
+
@obj.command_set?.should be_false
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "with value set to nil" do
|
80
|
+
it "returns false" do
|
81
|
+
@obj.stub!(:value).and_return(nil)
|
82
|
+
@obj.command_set?.should be_false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper'))
|
2
|
+
require 'meac_control/command/inlet_temp'
|
3
|
+
|
4
|
+
describe MEACControl::Command::InletTemp do
|
5
|
+
before(:each) do
|
6
|
+
@cmd = MEACControl::Command::InletTemp.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it_should_behave_like "a class that includes MEACControl::Command::Generic"
|
10
|
+
|
11
|
+
it "has set the command to 'InletTemp'" do
|
12
|
+
@cmd.command.should == 'InletTemp'
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
2
|
+
require 'meac_control/device'
|
3
|
+
|
4
|
+
describe MEACControl::Device do
|
5
|
+
describe "#id" do
|
6
|
+
it "returns the device id" do
|
7
|
+
MEACControl::Device.new(34).id.should == 34
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#name" do
|
12
|
+
it "returns the device name" do
|
13
|
+
device = MEACControl::Device.new(23)
|
14
|
+
device.name = "fooac"
|
15
|
+
device.name.should == "fooac"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "will set the name value with the initializer option :name" do
|
20
|
+
device = MEACControl::Device.new(22, :name => "foobarac")
|
21
|
+
device.name.should == "foobarac"
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
2
|
+
require 'meac_control/http'
|
3
|
+
|
4
|
+
describe MEACControl::HTTP do
|
5
|
+
describe "URI_TEMPLATE constant" do
|
6
|
+
it "can be used to build the correct uri" do
|
7
|
+
uri = sprintf(MEACControl::HTTP::URI_TEMPLATE, '10.0.0.1')
|
8
|
+
uri.should == 'http://10.0.0.1/servlet/MIMEReceiveServlet'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "DEFAULT_HEADER constant" do
|
13
|
+
it "has 'Accept' set to 'text/xml'" do
|
14
|
+
MEACControl::HTTP::DEFAULT_HEADER['Accept'].should == 'text/xml'
|
15
|
+
end
|
16
|
+
|
17
|
+
it "has 'Content-Type' set to 'text/xml'" do
|
18
|
+
MEACControl::HTTP::DEFAULT_HEADER['Content-Type'].should == 'text/xml'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
before(:each) do
|
23
|
+
@device = mock('device')
|
24
|
+
@command = mock('command')
|
25
|
+
@hostname = '127.0.0.1'
|
26
|
+
@uri = sprintf(MEACControl::HTTP::URI_TEMPLATE, @hostname)
|
27
|
+
end
|
28
|
+
|
29
|
+
describe ".get" do
|
30
|
+
before(:each) do
|
31
|
+
@xml = mock('xml_request', :to_xml => fixture_read('get-request.xml'))
|
32
|
+
|
33
|
+
HTTPClient.should_receive(:post).with(@uri, @xml.to_xml, MEACControl::HTTP::DEFAULT_HEADER).and_return do
|
34
|
+
mock('http_response', :content => fixture_read('get-response-ok.xml'))
|
35
|
+
end
|
36
|
+
|
37
|
+
MEACControl::XML::GetRequest.should_receive(:new).with(@device, @command).and_return(@xml)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "executes a get request" do
|
41
|
+
MEACControl::HTTP.get(@hostname, @device, @command)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "returns a response object" do
|
45
|
+
MEACControl::HTTP.get(@hostname, @device, @command).should be_ok
|
46
|
+
end
|
47
|
+
|
48
|
+
it "returns a response object which includes the request object" do
|
49
|
+
MEACControl::HTTP.get(@hostname, @device, @command).request.should == @xml
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe ".set" do
|
54
|
+
before(:each) do
|
55
|
+
@xml = mock('xml_request', :to_xml => fixture_read('set-request.xml'))
|
56
|
+
|
57
|
+
HTTPClient.should_receive(:post).with(@uri, @xml.to_xml, MEACControl::HTTP::DEFAULT_HEADER).and_return do
|
58
|
+
mock('http_response', :content => fixture_read('get-response-ok.xml'))
|
59
|
+
end
|
60
|
+
|
61
|
+
MEACControl::XML::SetRequest.should_receive(:new).with(@device, @command).and_return(@xml)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "executes a set request" do
|
65
|
+
MEACControl::HTTP.set(@hostname, @device, @command)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "returns a response object" do
|
69
|
+
MEACControl::HTTP.set(@hostname, @device, @command).should be_ok
|
70
|
+
end
|
71
|
+
|
72
|
+
it "returns a response object which includes the request object" do
|
73
|
+
MEACControl::HTTP.set(@hostname, @device, @command).request.should == @xml
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper'))
|
2
|
+
require 'meac_control/xml/get_request'
|
3
|
+
|
4
|
+
class Dev; end
|
5
|
+
class Cmd; end
|
6
|
+
|
7
|
+
class MyRequest < MEACControl::XML::AbstractRequest
|
8
|
+
def to_xml
|
9
|
+
xml_template('myRequest', :get)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe MEACControl::XML::AbstractRequest do
|
14
|
+
it "creates a get request with one device and a list of commands" do
|
15
|
+
req = MyRequest.new(:one, [:one, :two, :three])
|
16
|
+
req.should have(1).devices
|
17
|
+
req.should have(3).commands
|
18
|
+
end
|
19
|
+
|
20
|
+
it "creates a get request with a list of devices and commands" do
|
21
|
+
req = MyRequest.new([:one, :two], [:one, :two, :three])
|
22
|
+
req.should have(2).devices
|
23
|
+
req.should have(3).commands
|
24
|
+
end
|
25
|
+
|
26
|
+
it "creates a get request with one device and one command" do
|
27
|
+
req = MyRequest.new(:two, :one)
|
28
|
+
req.should have(1).devices
|
29
|
+
req.should have(1).commands
|
30
|
+
end
|
31
|
+
|
32
|
+
it "fails to create a valid get request with an empty device list" do
|
33
|
+
lambda {
|
34
|
+
MyRequest.new([], [:one, :two, :three])
|
35
|
+
}.should raise_error(MEACControl::XML::Request::EmptyDeviceList)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "fails to create a valid get request with a nil device" do
|
39
|
+
lambda {
|
40
|
+
MyRequest.new(nil, [:one, :two, :three])
|
41
|
+
}.should raise_error(MEACControl::XML::Request::EmptyDeviceList)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "fails to create a valid get request with a nil command" do
|
45
|
+
lambda {
|
46
|
+
MyRequest.new([:one, :two, :three], nil)
|
47
|
+
}.should raise_error(MEACControl::XML::Request::EmptyCommandList)
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#xml_template" do
|
51
|
+
it "is not accessible as an instance method" do
|
52
|
+
req = MyRequest.new(:one, :two)
|
53
|
+
lambda { req.xml_template }.should raise_error(NoMethodError)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Example XML output:
|
58
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
59
|
+
# <Packet>
|
60
|
+
# <Command>getRequest</Command>
|
61
|
+
# <DatabaseManager>
|
62
|
+
# <Mnet Group="23" Drive="*"/>
|
63
|
+
# </DatabaseManager>
|
64
|
+
# </Packet>
|
65
|
+
describe "#to_xml" do
|
66
|
+
before(:each) do
|
67
|
+
device = mock(Dev, :id => 23)
|
68
|
+
commands = [
|
69
|
+
mock(Cmd, :hash_for => {:Command1 => '*'}),
|
70
|
+
mock(Cmd, :hash_for => {:Command2 => '*'}),
|
71
|
+
mock(Cmd, :hash_for => {:Command3 => '*'})
|
72
|
+
]
|
73
|
+
@req = MyRequest.new(device, commands)
|
74
|
+
@xml = Nokogiri::XML(@req.to_xml)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "has one root node named 'Packet'" do
|
78
|
+
@xml.root.name.should == 'Packet'
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "<Packet>" do
|
82
|
+
it "has one child node named 'Command'" do
|
83
|
+
@xml.root.search('/Packet/Command').size.should == 1
|
84
|
+
end
|
85
|
+
|
86
|
+
it "has one child node named 'DatabaseManager'" do
|
87
|
+
@xml.root.search('/Packet/DatabaseManager').size.should == 1
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "<Command>" do
|
92
|
+
it "has a text of 'getRequest'" do
|
93
|
+
@xml.root.at('/Packet/Command').text.should == "myRequest"
|
94
|
+
end
|
95
|
+
|
96
|
+
it "has a parent node named 'Packet'" do
|
97
|
+
@xml.root.at('/Packet/Command').parent.name.should == "Packet"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "<DatabaseManager>" do
|
102
|
+
it "has one chile node named 'Mnet'" do
|
103
|
+
@xml.root.search('/Packet/DatabaseManager/Mnet').size.should == 1
|
104
|
+
end
|
105
|
+
|
106
|
+
it "has a parent node named 'Packet'" do
|
107
|
+
@xml.root.at('/Packet/DatabaseManager').parent.name.should == "Packet"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "<Mnet>" do
|
112
|
+
before(:each) do
|
113
|
+
@mnet = @xml.root.at('/Packet/DatabaseManager/Mnet')
|
114
|
+
end
|
115
|
+
|
116
|
+
it "has a 'Group' attribute with value '23'" do
|
117
|
+
@mnet.key?('Group').should be_true
|
118
|
+
@mnet.attribute('Group').value.should == "23"
|
119
|
+
end
|
120
|
+
|
121
|
+
it "has a 'Command1' attribute with value '*'" do
|
122
|
+
@mnet.key?('Command1').should be_true
|
123
|
+
@mnet.attribute('Command1').value.should == "*"
|
124
|
+
end
|
125
|
+
|
126
|
+
it "has a 'Command2' attribute with value '*'" do
|
127
|
+
@mnet.key?('Command2').should be_true
|
128
|
+
@mnet.attribute('Command2').value.should == "*"
|
129
|
+
end
|
130
|
+
|
131
|
+
it "has a 'Command3' attribute with value '*'" do
|
132
|
+
@mnet.key?('Command3').should be_true
|
133
|
+
@mnet.attribute('Command3').value.should == "*"
|
134
|
+
end
|
135
|
+
|
136
|
+
it "has a parent node named 'DatabaseManager'" do
|
137
|
+
@xml.root.at('/Packet/DatabaseManager/Mnet').parent.name.should == "DatabaseManager"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper'))
|
2
|
+
require 'meac_control/xml/get_request'
|
3
|
+
|
4
|
+
class Dev; end
|
5
|
+
class Cmd; end
|
6
|
+
|
7
|
+
describe MEACControl::XML::GetRequest do
|
8
|
+
it "inherits from the MEACControl::XML::AbstractRequest class" do
|
9
|
+
req = MEACControl::XML::GetRequest.new(:one, [:one, :two, :three])
|
10
|
+
req.should be_kind_of(MEACControl::XML::AbstractRequest)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#to_xml" do
|
14
|
+
it "returns a xml string with 'getRequest' in the <Command> element" do
|
15
|
+
device = mock(Dev, :id => 23)
|
16
|
+
commands = [
|
17
|
+
mock(Cmd, :hash_for => {:Command1 => 'ON'}),
|
18
|
+
mock(Cmd, :hash_for => {:Command2 => 'ON'}),
|
19
|
+
mock(Cmd, :hash_for => {:Command3 => 'ON'})
|
20
|
+
]
|
21
|
+
req = MEACControl::XML::GetRequest.new(device, commands)
|
22
|
+
xml = Nokogiri::XML(req.to_xml)
|
23
|
+
xml.root.at('/Packet/Command').text.should == "getRequest"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper'))
|
2
|
+
require 'meac_control/xml/response'
|
3
|
+
|
4
|
+
describe MEACControl::XML::Response do
|
5
|
+
before(:each) do
|
6
|
+
@string_ok = fixture_read('get-response-ok.xml')
|
7
|
+
@string_error = fixture_read('get-response-error.xml')
|
8
|
+
@request = mock('xml_request')
|
9
|
+
end
|
10
|
+
|
11
|
+
it "creates a response from a xml string" do
|
12
|
+
response = MEACControl::XML::Response.new(@string_ok)
|
13
|
+
response.xml.should be_a(Nokogiri::XML::Document)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "creates a response from a xml string and a request object" do
|
17
|
+
response = MEACControl::XML::Response.new(@string_ok, @request)
|
18
|
+
response.xml.should be_a(Nokogiri::XML::Document)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "will raise an error if the XML response has no root node" do
|
22
|
+
lambda { MEACControl::XML::Response.new('foo') }.should raise_error(MEACControl::XML::InvalidResponse)
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#request" do
|
26
|
+
it "returns the request object" do
|
27
|
+
response = MEACControl::XML::Response.new(@string_ok, @request)
|
28
|
+
response.request.should == @request
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#to_xml" do
|
33
|
+
it "returns the response xml string" do
|
34
|
+
response = MEACControl::XML::Response.new(@string_ok)
|
35
|
+
response.to_xml.should == @string_ok
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#ok?" do
|
40
|
+
it "returns true if the response has no error messages" do
|
41
|
+
response = MEACControl::XML::Response.new(@string_ok)
|
42
|
+
response.ok?.should be_true
|
43
|
+
end
|
44
|
+
|
45
|
+
it "returns false if the response has an error message" do
|
46
|
+
response = MEACControl::XML::Response.new(@string_error)
|
47
|
+
response.ok?.should be_false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#errors?" do
|
52
|
+
it "returns true if the response has an error message" do
|
53
|
+
response = MEACControl::XML::Response.new(@string_error)
|
54
|
+
response.errors?.should be_true
|
55
|
+
end
|
56
|
+
|
57
|
+
it "returns false if the response has no error message" do
|
58
|
+
response = MEACControl::XML::Response.new(@string_ok)
|
59
|
+
response.errors?.should be_false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#errors" do
|
64
|
+
it "returns a list of hashes with the error messages" do
|
65
|
+
response = MEACControl::XML::Response.new(@string_error)
|
66
|
+
response.errors.should == [{'Point' => 'geRequest', 'Code' => '0102', 'Message' => 'Insufficiency Attribute'}]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#error_messages" do
|
71
|
+
it "returns a list of error message strings" do
|
72
|
+
response = MEACControl::XML::Response.new(@string_error)
|
73
|
+
response.error_messages.should == ['Insufficiency Attribute']
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper'))
|
2
|
+
require 'meac_control/xml/set_request'
|
3
|
+
|
4
|
+
class Dev; end
|
5
|
+
class Cmd; end
|
6
|
+
|
7
|
+
describe MEACControl::XML::SetRequest do
|
8
|
+
it "inherits from the MEACControl::XML::AbstractRequest class" do
|
9
|
+
req = MEACControl::XML::SetRequest.new(:one, [:one, :two, :three])
|
10
|
+
req.should be_kind_of(MEACControl::XML::AbstractRequest)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#to_xml" do
|
14
|
+
it "returns a xml string with 'setRequest' in the <Command> element" do
|
15
|
+
device = mock(Dev, :id => 23)
|
16
|
+
commands = [
|
17
|
+
mock(Cmd, :hash_for => {:Command1 => 'ON'}),
|
18
|
+
mock(Cmd, :hash_for => {:Command2 => 'ON'}),
|
19
|
+
mock(Cmd, :hash_for => {:Command3 => 'ON'})
|
20
|
+
]
|
21
|
+
req = MEACControl::XML::SetRequest.new(device, commands)
|
22
|
+
xml = Nokogiri::XML(req.to_xml)
|
23
|
+
xml.root.at('/Packet/Command').text.should == "setRequest"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'spec'
|
4
|
+
|
5
|
+
SPEC_ROOT = Pathname(__FILE__).dirname.expand_path
|
6
|
+
$:.unshift File.join(SPEC_ROOT.parent, 'lib')
|
7
|
+
|
8
|
+
# Pull the shared examples.
|
9
|
+
require File.join(SPEC_ROOT, 'support', 'shared_examples')
|
10
|
+
|
11
|
+
def fixture_read(filename)
|
12
|
+
File.read(File.join(SPEC_ROOT, 'fixtures', filename))
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: meac_control
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bernd Ahlers
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-03 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.9
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: httpclient
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: nokogiri
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
description: Library to communicate with a Mitsubishi Electric G-50A centralized controller
|
46
|
+
email: bernd@tuneafish.de
|
47
|
+
executables: []
|
48
|
+
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files:
|
52
|
+
- LICENSE
|
53
|
+
- README.md
|
54
|
+
files:
|
55
|
+
- LICENSE
|
56
|
+
- README.md
|
57
|
+
- Rakefile
|
58
|
+
- VERSION.yml
|
59
|
+
- lib/meac_control.rb
|
60
|
+
- lib/meac_control/command.rb
|
61
|
+
- lib/meac_control/command/drive.rb
|
62
|
+
- lib/meac_control/command/fan_speed.rb
|
63
|
+
- lib/meac_control/command/generic.rb
|
64
|
+
- lib/meac_control/command/inlet_temp.rb
|
65
|
+
- lib/meac_control/device.rb
|
66
|
+
- lib/meac_control/http.rb
|
67
|
+
- lib/meac_control/xml.rb
|
68
|
+
- lib/meac_control/xml/abstract_request.rb
|
69
|
+
- lib/meac_control/xml/exceptions.rb
|
70
|
+
- lib/meac_control/xml/get_request.rb
|
71
|
+
- lib/meac_control/xml/response.rb
|
72
|
+
- lib/meac_control/xml/set_request.rb
|
73
|
+
- spec/fixtures/get-request.xml
|
74
|
+
- spec/fixtures/get-response-error.xml
|
75
|
+
- spec/fixtures/get-response-ok.xml
|
76
|
+
- spec/fixtures/set-request.xml
|
77
|
+
- spec/lib/meac_control/command/drive_spec.rb
|
78
|
+
- spec/lib/meac_control/command/fan_speed_spec.rb
|
79
|
+
- spec/lib/meac_control/command/generic_spec.rb
|
80
|
+
- spec/lib/meac_control/command/inlet_temp_spec.rb
|
81
|
+
- spec/lib/meac_control/device_spec.rb
|
82
|
+
- spec/lib/meac_control/http_spec.rb
|
83
|
+
- spec/lib/meac_control/xml/abstract_request_spec.rb
|
84
|
+
- spec/lib/meac_control/xml/get_request_spec.rb
|
85
|
+
- spec/lib/meac_control/xml/response_spec.rb
|
86
|
+
- spec/lib/meac_control/xml/set_request_spec.rb
|
87
|
+
- spec/spec.opts
|
88
|
+
- spec/spec_helper.rb
|
89
|
+
- spec/support/shared_examples.rb
|
90
|
+
has_rdoc: true
|
91
|
+
homepage: http://github.com/bernd/meac_control
|
92
|
+
licenses: []
|
93
|
+
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options:
|
96
|
+
- --charset=UTF-8
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: "0"
|
104
|
+
version:
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: "0"
|
110
|
+
version:
|
111
|
+
requirements: []
|
112
|
+
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 1.3.5
|
115
|
+
signing_key:
|
116
|
+
specification_version: 3
|
117
|
+
summary: Library to communicate with a Mitsubishi Electric G-50A centralized controller
|
118
|
+
test_files:
|
119
|
+
- spec/lib/meac_control/command/drive_spec.rb
|
120
|
+
- spec/lib/meac_control/command/fan_speed_spec.rb
|
121
|
+
- spec/lib/meac_control/command/generic_spec.rb
|
122
|
+
- spec/lib/meac_control/command/inlet_temp_spec.rb
|
123
|
+
- spec/lib/meac_control/http_spec.rb
|
124
|
+
- spec/lib/meac_control/device_spec.rb
|
125
|
+
- spec/lib/meac_control/xml/get_request_spec.rb
|
126
|
+
- spec/lib/meac_control/xml/set_request_spec.rb
|
127
|
+
- spec/lib/meac_control/xml/abstract_request_spec.rb
|
128
|
+
- spec/lib/meac_control/xml/response_spec.rb
|
129
|
+
- spec/spec_helper.rb
|
130
|
+
- spec/support/shared_examples.rb
|