line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Device::Power::Synaccess::NP05B; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# ABSTRACT: Manage and monitor the Synaccess NP-05B networked power strip |
4
|
|
|
|
|
|
|
|
5
|
4
|
|
|
4
|
|
417085
|
use strict; |
|
4
|
|
|
|
|
33
|
|
|
4
|
|
|
|
|
94
|
|
6
|
4
|
|
|
4
|
|
16
|
use warnings; |
|
4
|
|
|
|
|
5
|
|
|
4
|
|
|
|
|
110
|
|
7
|
4
|
|
|
4
|
|
2951
|
use Net::Telnet; |
|
4
|
|
|
|
|
122389
|
|
|
4
|
|
|
|
|
6584
|
|
8
|
|
|
|
|
|
|
our $VERSION = '1.03'; |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 NAME |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
Device::Power::Synaccess::NP05B -- Manage and monitor the Synaccess NP05B networked power strip |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 SYNOPSIS |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
my $np = Device::Power::Synaccess::NP05B->new(addr => '10.0.0.1'); |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# must initiate a connection and log in before issuing commands: |
19
|
|
|
|
|
|
|
($ok, $err) = $np->connect; |
20
|
|
|
|
|
|
|
($ok, $err) = $np->login; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# are we still connected? |
23
|
|
|
|
|
|
|
$np->is_connected or die "whoops"; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# get the status of the connection: |
26
|
|
|
|
|
|
|
say $np->cond; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# get the on/off status of the power outlets: |
29
|
|
|
|
|
|
|
($ok, $hashref) = $np->power_status; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# turn on outlet 2: |
32
|
|
|
|
|
|
|
($ok, $err) = $np->power_set(2, 1) |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# get the full system status, including network attributes: |
35
|
|
|
|
|
|
|
($ok, $hashref) = $np->status; |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# must log out cleanly or device can get confused: |
38
|
|
|
|
|
|
|
($ok, $err) = $np->logout; |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=head1 ABSTRACT |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
Synaccess makes a power strip product called the C which can be remotely accessed and controlled via telnet or http. |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
C accesses the C via telnet and provides programmatic access to some of its functions, notably system status and turning on/off specific power outlets. |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=head1 METHODS |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=head2 new |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
my $np = Device::Power::Synaccess::NP05B->new(); |
52
|
|
|
|
|
|
|
my $np = Device::Power::Synaccess::NP05B->new(addr => '10.0.0.6', ...); |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
Instantiates an C object. It takes some optional named parameters: |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=over 4 |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
=item * addr => string |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
Specify the IP address of the C device. Defaults to "192.168.1.100", which was the factory default of the device sold to me. |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=item * user => string |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
Specify the login username. Defaults to "admin", which was the factory default of the device sold to me. |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=item * pass => string |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
Specify the login password. Defaults to "admin", which was the factory default of the device sold to me. |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=back |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
A new C object will have a condition of "disconnected". |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=cut |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub new { |
77
|
4
|
|
|
4
|
1
|
49
|
my ($class, %opt_hr) = @_; |
78
|
4
|
|
|
|
|
32
|
my $self = { |
79
|
|
|
|
|
|
|
opt_hr => \%opt_hr, |
80
|
|
|
|
|
|
|
ok => 'OK', |
81
|
|
|
|
|
|
|
n_err => 0, |
82
|
|
|
|
|
|
|
n_warn => 0, |
83
|
|
|
|
|
|
|
err => '', |
84
|
|
|
|
|
|
|
err_ar => [], |
85
|
|
|
|
|
|
|
cond => 'disconnected', |
86
|
|
|
|
|
|
|
status => undef, |
87
|
|
|
|
|
|
|
buffer => undef |
88
|
|
|
|
|
|
|
}; |
89
|
4
|
|
|
|
|
8
|
bless ($self, $class); |
90
|
|
|
|
|
|
|
|
91
|
4
|
|
|
|
|
7
|
foreach my $k0 (keys %{$self->{opt_hr}}) { |
|
4
|
|
|
|
|
25
|
|
92
|
4
|
|
|
|
|
17
|
my $k1 = join('_', split(/-/, $k0)); |
93
|
4
|
50
|
|
|
|
13
|
next if ($k0 eq $k1); |
94
|
0
|
|
|
|
|
0
|
$self->{opt_hr}->{$k1} = $self->{opt_hr}->{$k0}; |
95
|
0
|
|
|
|
|
0
|
delete $self->{opt_hr}->{$k0}; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
4
|
|
|
|
|
18
|
$self->addr = $self->opt('addr', '192.168.1.100'); |
99
|
4
|
|
|
|
|
15
|
$self->user = $self->opt('user', 'admin'); |
100
|
4
|
|
|
|
|
12
|
$self->pass = $self->opt('pass', 'admin'); |
101
|
|
|
|
|
|
|
|
102
|
4
|
|
|
|
|
11
|
return $self; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=head2 connect |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
my ($ok, $err) = $np->connect; |
108
|
|
|
|
|
|
|
die "connect: $err" unless ($ok eq 'OK'); |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
Attempt to open a telnet connection to the C device. This must be done before attempting C or any other method. |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
After successful connection, the C object will have a condition of "connected". |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
Returns ('OK', '') on success, or ('ERROR', $error_message) on failure, where $error_message is a short string describing the error (or, in some cases, the exception string thrown by L). |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=cut |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub connect { |
119
|
2
|
|
|
2
|
1
|
962
|
my ($self) = @_; |
120
|
2
|
|
|
|
|
2
|
my $t; # reference to Net::Telnet object or Mock::Net::Telnet |
121
|
2
|
50
|
|
|
|
6
|
if ($self->opt('telnet_or','')) { |
122
|
|
|
|
|
|
|
# Using mocked object for unit testing |
123
|
2
|
|
|
|
|
6
|
$t = $self->opt('telnet_or'); |
124
|
|
|
|
|
|
|
} else { |
125
|
0
|
|
|
|
|
0
|
$t = new Net::Telnet(Timeout => 3, Prompt => '/>$/'); |
126
|
|
|
|
|
|
|
} |
127
|
2
|
|
|
|
|
6
|
$t->open($self->addr); |
128
|
2
|
|
|
|
|
3
|
$self->{telnet_or} = $t; |
129
|
2
|
|
|
|
|
4
|
my @results; |
130
|
2
|
|
|
|
|
1001153
|
select(undef, undef, undef, 0.5); # to avoid command line pollution on remote end -- mysterious \0's injected. |
131
|
2
|
|
|
|
|
19
|
eval { @results = $t->cmd("ver") }; |
|
2
|
|
|
|
|
27
|
|
132
|
2
|
50
|
|
|
|
8
|
if (@results) { |
133
|
2
|
|
|
|
|
13
|
$self->cond = 'connected'; |
134
|
2
|
|
|
|
|
7
|
$self->{buffer} = \@results; |
135
|
2
|
|
|
|
|
9
|
return $self->ok(); |
136
|
|
|
|
|
|
|
} |
137
|
0
|
|
|
|
|
0
|
$self->cond = 'disconnected'; |
138
|
0
|
|
|
|
|
0
|
return $self->err("did not connect", $@); |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=head2 login |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
my ($ok, $err) = $np->login; |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
Attempt to log in to the C device. This must be done before attempting any other access or control methods. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
Once successfully logged in, it is inadvisable to terminate the connection without first calling the C method. The device can get into a sick state otherwise and misbehave in subsequent connections. |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
After successful login, the C object will have a condition of "authenticated". |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
Returns ('OK', '') on success, or ('ERROR', $error_message) on failure, where $error_message is a short string describing the error (or, in some cases, the exception string thrown by L). |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=cut |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub login { # Can't use telnet_or->login method because Synaccess uses nonstandard prompt format that telnet_or cannot accomodate. |
156
|
2
|
|
|
2
|
1
|
700
|
my ($self) = @_; |
157
|
2
|
100
|
|
|
|
7
|
return $self->err("not connected") unless ($self->is_connected); |
158
|
1
|
|
|
|
|
3
|
my $t = $self->{telnet_or}; |
159
|
1
|
|
|
|
|
6
|
$t->print(""); # Sometimes there's garbage on the commandline |
160
|
1
|
|
|
|
|
4
|
$t->print("login"); |
161
|
1
|
|
|
|
|
1000150
|
sleep(1); |
162
|
1
|
|
|
|
|
16
|
$t->print($self->user); |
163
|
1
|
|
|
|
|
1000096
|
sleep(1); |
164
|
1
|
|
|
|
|
22
|
$t->print($self->pass); |
165
|
1
|
|
|
|
|
1000098
|
sleep(1); |
166
|
1
|
|
|
|
|
9
|
my @results; |
167
|
1
|
|
|
|
|
4
|
eval { @results = $t->cmd("ver") }; |
|
1
|
|
|
|
|
12
|
|
168
|
1
|
50
|
|
|
|
5
|
if (@results) { |
169
|
1
|
|
|
|
|
6
|
$self->cond = 'authenticated'; |
170
|
1
|
|
|
|
|
6
|
$self->{buffer} = \@results; |
171
|
1
|
|
|
|
|
4
|
return $self->ok(); |
172
|
|
|
|
|
|
|
} |
173
|
0
|
|
|
|
|
0
|
$self->cond = 'disconnected'; |
174
|
0
|
|
|
|
|
0
|
return $self->err("login failed", $@); |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=head2 is_connected |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
say $np->is_connected ? "still connected" : "not connected"; |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
Check the connection status. Returns 1 if C condition is "connected" or "authenticated", or 0 otherwise. |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=cut |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub is_connected { |
186
|
8
|
|
|
8
|
1
|
15
|
my ($self) = @_; |
187
|
8
|
100
|
|
|
|
12
|
return 1 if ($self->cond eq 'connected'); |
188
|
7
|
100
|
|
|
|
9
|
return 1 if ($self->cond eq 'authenticated'); |
189
|
1
|
|
|
|
|
3
|
return 0; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=head2 logout |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
my ($ok, $err) = $np->logout; |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
Needed to cleanly terminate the remote connection. |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
After successful logout, the C object will have a condition of "disconnected", and further access will require calling L and L. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
Returns ('OK', '') on success, or ('ERROR', $error_message) on failure, where $error_message is a short string describing the error (or, in some cases, the exception string thrown by L). |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=cut |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
sub logout { |
205
|
1
|
|
|
1
|
1
|
433
|
my ($self) = @_; |
206
|
1
|
50
|
|
|
|
18
|
return $self->err("not connected") unless ($self->is_connected); |
207
|
1
|
|
|
|
|
17
|
my @results; |
208
|
1
|
|
|
|
|
3
|
eval { @results = ($self->{telnet_or}->cmd("ver"), $self->{telnet_or}->cmd("logout")) }; |
|
1
|
|
|
|
|
5
|
|
209
|
1
|
|
|
|
|
5
|
$self->{telnet_or}->close(); |
210
|
1
|
|
|
|
|
2
|
$self->{telnet_or} = undef; |
211
|
1
|
|
|
|
|
3
|
$self->cond = 'disconnected'; |
212
|
1
|
|
|
|
|
4
|
$self->{buffer} = [@results, $@]; |
213
|
1
|
|
|
|
|
3
|
return $self->ok(); |
214
|
|
|
|
|
|
|
# return $self->warn("might have disconnected uncleanly", $@); |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=head2 power_status |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
my ($ok, $hashref) = $np->power_status; |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
Retrieves the on/off status of the C device's power outlets in the form of a hashref which keys on the port number to either 0 (off) or 1 (on). |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
For instance, if ports 1 2 and 3 are on and ports 4 and 5 are off, $hashref will reference: |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
{1 => 1, 2 => 1, 3 => 1, 4 => 0, 5 => 0} |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
Returns ('OK', $hashref) on success, or ('ERROR', $error_message) on failure, where $error_message is a short string describing the error (or, in some cases, the exception string thrown by L). |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=cut |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
sub power_status { |
232
|
2
|
|
|
2
|
1
|
674
|
my ($self) = @_; |
233
|
2
|
50
|
|
|
|
7
|
return $self->err("not connected") unless ($self->is_connected); |
234
|
2
|
|
|
|
|
3
|
my @results; |
235
|
2
|
|
|
|
|
3
|
eval { @results = ($self->{telnet_or}->cmd("ver"),$self->{telnet_or}->cmd("pshow"),$self->{telnet_or}->cmd("ver")) }; |
|
2
|
|
|
|
|
6
|
|
236
|
2
|
|
|
|
|
5
|
$self->{buffer} = \@results; |
237
|
2
|
50
|
|
|
|
5
|
return $self->err("telnet exception", $@) unless (@results); |
238
|
2
|
|
|
|
|
4
|
my %ps; |
239
|
|
|
|
|
|
|
# "\rPort | Name |Status\n","\r 1 | Outlet1 | ON | 2 | Outlet2 | ON | |
240
|
|
|
|
|
|
|
# 3 | Outlet3 | ON | 4 | Outlet4 | OFF| |
241
|
|
|
|
|
|
|
# 5 | Outlet5 | ON |\n" |
242
|
2
|
|
|
|
|
4
|
foreach my $s (@results) { |
243
|
8
|
100
|
|
|
|
21
|
next unless ($s =~ /^\s+\d+\s+\|\s+Outlet\d/); |
244
|
2
|
|
|
|
|
17
|
foreach my $outlet (split(/(\d+\s+\|\s+Outlet\d+\s+\|\s+[OFN]+\s*\|)/, $s)) { |
245
|
20
|
100
|
|
|
|
56
|
$ps{$1} = $2 eq 'ON' ? 1 : 0 if ($outlet =~ /\s+Outlet(\d+)\s+\|\s+([OFN]+)\s*\|/); |
|
|
100
|
|
|
|
|
|
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
} |
248
|
2
|
50
|
|
|
|
5
|
return $self->err("could not parse power status", \@results) unless (keys %ps); |
249
|
2
|
|
|
|
|
4
|
return $self->ok(\%ps); |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=head2 power_set |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
my ($ok, $hashref) = $np->power_set(3, 1); |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
Turns a specified C device's power outlet on or off. Its first parameter is the outlet number (1..5 on my device), and the second parameter is either 0 (to turn it off) or 1 (to turn it on). |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
Upon success, the returned $hashref is identical in format and semantics to the one returned by L. |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
Returns ('OK', $hashref) on success, or ('ERROR', $error_message) on failure, where $error_message is a short string describing the error (or, in some cases, the exception string thrown by L). |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=cut |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
sub power_set { |
265
|
1
|
|
|
1
|
1
|
420
|
my ($self, $outlet, $on_or_off) = @_; |
266
|
1
|
50
|
|
|
|
4
|
return $self->err("not connected") unless ($self->is_connected); |
267
|
1
|
|
|
|
|
10
|
$self->{telnet_or}->cmd("ver"); |
268
|
1
|
|
|
|
|
9
|
$self->{telnet_or}->cmd("pset $outlet $on_or_off"); |
269
|
1
|
|
|
|
|
3
|
$self->{telnet_or}->cmd("ver"); |
270
|
1
|
|
|
|
|
2
|
my ($ok, $ps_hr, @errs) = $self->power_status; |
271
|
1
|
50
|
|
|
|
4
|
return ('ERROR', $ps_hr, @errs) unless ($ok eq 'OK'); |
272
|
1
|
50
|
|
|
|
4
|
my $normalized_on_or_off = $on_or_off ? 1 : 0; |
273
|
1
|
50
|
|
|
|
4
|
return $self->warn('outlet number out of range') unless(defined($ps_hr->{$outlet})); |
274
|
1
|
50
|
|
|
|
5
|
return $self->err('unexpected outlet status') unless($ps_hr->{$outlet} == $normalized_on_or_off); |
275
|
1
|
|
|
|
|
3
|
return $self->ok($ps_hr); |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=head2 status |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
my ($ok, $hashref) = $np->status; |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
Retrieves the full system status of the C device. The returned hashref is a bit complex: |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
{ |
285
|
|
|
|
|
|
|
'src_ip' => '0.0.0.0', |
286
|
|
|
|
|
|
|
's_mask' => '255.255.0.0', |
287
|
|
|
|
|
|
|
'source' => 'static', |
288
|
|
|
|
|
|
|
'port_telnet' => '23', |
289
|
|
|
|
|
|
|
'port_http' => '80', |
290
|
|
|
|
|
|
|
'model' => 'NP-05B', |
291
|
|
|
|
|
|
|
'mask' => '255.255.0.0', |
292
|
|
|
|
|
|
|
'eth' => 'on', |
293
|
|
|
|
|
|
|
'ip' => '192.168.1.100', |
294
|
|
|
|
|
|
|
's_ip' => '192.168.1.100', |
295
|
|
|
|
|
|
|
's_gw' => '192.168.1.1', |
296
|
|
|
|
|
|
|
'mac' => '00:90:c2:12:34:56', |
297
|
|
|
|
|
|
|
'power_hr' => { |
298
|
|
|
|
|
|
|
'2' => 1, |
299
|
|
|
|
|
|
|
'5' => 1, |
300
|
|
|
|
|
|
|
'3' => 1, |
301
|
|
|
|
|
|
|
'1' => 1, |
302
|
|
|
|
|
|
|
'4' => 1 |
303
|
|
|
|
|
|
|
}, |
304
|
|
|
|
|
|
|
'gw' => '192.168.1.1' |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
Returns ('OK', $hashref) on success, or ('ERROR', $error_message) on failure, where $error_message is a short string describing the error (or, in some cases, the exception string thrown by L). |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
=cut |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
sub status { |
312
|
2
|
|
|
2
|
1
|
808
|
my ($self) = @_; |
313
|
2
|
50
|
|
|
|
6
|
return $self->err("not connected") unless ($self->is_connected); |
314
|
2
|
|
|
|
|
3
|
my @results; |
315
|
2
|
|
|
|
|
3
|
eval { @results = ($self->{telnet_or}->cmd("ver"),$self->{telnet_or}->cmd("sysshow"),$self->{telnet_or}->cmd("ver")) }; |
|
2
|
|
|
|
|
6
|
|
316
|
2
|
|
|
|
|
5
|
$self->{buffer} = \@results; |
317
|
2
|
50
|
|
|
|
5
|
return $self->err("telnet exception", $@) unless (@results); |
318
|
2
|
|
|
|
|
3
|
my %st_h; |
319
|
2
|
|
|
|
|
4
|
push @results, ''; # to make lookahead safe |
320
|
2
|
|
|
|
|
5
|
for (my $i = 0; $i < @results; $i++) { # yes, really, a C-style for loop .. easiest way to parse this evil soup |
321
|
26
|
|
|
|
|
27
|
my $s = $results[$i]; |
322
|
26
|
|
|
|
|
20
|
my $v = $results[$i+1]; |
323
|
26
|
50
|
|
|
|
37
|
if ($s =~ /^\s*Sys\s?Name\s*:\s*([^\s]+)/) { $st_h{'model'} = $1; } |
|
0
|
|
|
|
|
0
|
|
324
|
26
|
50
|
33
|
|
|
35
|
if ($s =~ /^\s*IP Static or DHCP/ && $v =~ /Using (\w+)/) { $st_h{'source'} = lc($1); } |
|
0
|
|
|
|
|
0
|
|
325
|
26
|
100
|
|
|
|
36
|
if ($s =~ /^\s*IP-Mask-GW\s*:\s*([^-]+)-([^-]+)-([^\s]+)/) { ($st_h{'ip'}, $st_h{'mask'}, $st_h{'gw'}) = ($1, $2, $3); } |
|
2
|
|
|
|
|
10
|
|
326
|
26
|
100
|
|
|
|
34
|
if ($s =~ /^\s*Static IP\/Mask\/Gateway\s*:\s*([^-]+)-([^-]+)-([^\s]+)/) { ($st_h{'s_ip'}, $st_h{'s_mask'}, $st_h{'s_gw'}) = ($1, $2, $3); } |
|
2
|
|
|
|
|
7
|
|
327
|
26
|
100
|
|
|
|
32
|
if ($s =~ /^\s*Ethernet Port is (\w+)/) { $st_h{'eth'} = lc($1); } |
|
2
|
|
|
|
|
5
|
|
328
|
26
|
100
|
|
|
|
33
|
if ($s =~ /^\s*HTTP\/Telnet Port .s\s*:\s*(\d+)[^\d]+(\d+)/) { ($st_h{'port_http'}, $st_h{'port_telnet'}) = ($1, $2); } |
|
2
|
|
|
|
|
7
|
|
329
|
26
|
100
|
|
|
|
34
|
if ($s =~ /^\s*MAC Address\s*:\s*([\w\:]+)/) { $st_h{'mac'} = lc($1); } |
|
2
|
|
|
|
|
5
|
|
330
|
26
|
100
|
66
|
|
|
44
|
if ($s =~ /^\s*Designated Source IP/ && $v =~ /^\s*(\d+\.\d+\.\d+\.\d+)/) { $st_h{'src_ip'} = $1; } |
|
2
|
|
|
|
|
5
|
|
331
|
26
|
100
|
|
|
|
57
|
if ($s =~ /^\s*Outlet Status[^:]+: ([\d\s]+)/) { |
332
|
2
|
|
|
|
|
3
|
my $outlets = $1; |
333
|
2
|
|
|
|
|
3
|
my $ix = 1; |
334
|
2
|
|
|
|
|
3
|
$st_h{'power_hr'} = {}; |
335
|
2
|
|
|
|
|
8
|
foreach my $o (split(/\s+/, $outlets)) { |
336
|
10
|
|
|
|
|
19
|
$st_h{'power_hr'}->{$ix++} = int($o); |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
} |
340
|
2
|
50
|
|
|
|
7
|
return $self->err('no recognizable status', \@results) unless (keys %st_h); |
341
|
2
|
|
|
|
|
3
|
$self->{status} = \%st_h; |
342
|
2
|
|
|
|
|
4
|
return $self->ok(\%st_h); |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=head1 ACCESSORS |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
=head2 addr |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
my $address = $np->addr; |
350
|
|
|
|
|
|
|
$np->addr = '10.0.0.6'; |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
Get/set the C attribute, which determines where L will attempt to open a connection. |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
=head2 user |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
my $username = $np->user; |
357
|
|
|
|
|
|
|
$np->addr = 'bob'; |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
Get/set the C attribute, which must be correct for L to work. |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
=head2 pass |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
my $password = $np->pass; |
364
|
|
|
|
|
|
|
$np->pass = 'sekrit'; |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
Get/set the C attribute, which must be correct for L to work. |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
=head2 cond |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
my $condition = $np->cond; |
371
|
|
|
|
|
|
|
$np->addr = 'disconnected'; |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
Get/set the C attribute, which reflects the connectedness/authentication status of the object. |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
Setting this attribute yourself is B. |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=cut |
378
|
|
|
|
|
|
|
|
379
|
8
|
|
|
8
|
1
|
29
|
sub addr :lvalue { $_[0]->{addr} } |
380
|
7
|
|
|
7
|
1
|
38
|
sub user :lvalue { $_[0]->{user} } |
381
|
7
|
|
|
7
|
1
|
31
|
sub pass :lvalue { $_[0]->{pass} } |
382
|
21
|
|
|
21
|
1
|
64
|
sub cond :lvalue { $_[0]->{cond} } |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
sub all_is_well { |
385
|
9
|
|
|
9
|
0
|
12
|
my ($self) = @_; |
386
|
9
|
|
|
|
|
13
|
$self->{ok} = 'OK'; |
387
|
9
|
|
|
|
|
14
|
$self->{err} = ''; |
388
|
9
|
|
|
|
|
14
|
$self->{err_ar} = []; |
389
|
9
|
|
|
|
|
11
|
return; |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
sub opt { |
393
|
16
|
|
|
16
|
0
|
29
|
my ($self, $name, $default_value, $alt_hr) = @_; |
394
|
16
|
|
|
|
|
44
|
return def($self->{opt_hr}->{$name}, $alt_hr->{$name}, $default_value); |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
sub def { |
398
|
16
|
100
|
|
16
|
0
|
21
|
foreach my $v (@_) { return $v if (defined($v)); } |
|
40
|
|
|
|
|
93
|
|
399
|
0
|
|
|
|
|
0
|
return undef; |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
sub ok { |
403
|
9
|
|
|
9
|
0
|
25
|
my $self = shift(@_); |
404
|
9
|
|
|
|
|
21
|
$self->all_is_well(); |
405
|
9
|
|
|
|
|
38
|
return ('OK', @_); |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
sub err { |
409
|
1
|
|
|
1
|
0
|
2
|
my $self = shift(@_); |
410
|
1
|
|
|
|
|
1
|
$self->{n_err}++; |
411
|
1
|
|
|
|
|
2
|
$self->{err} = $_[0]; |
412
|
1
|
|
|
|
|
2
|
$self->{err_ar} = \@_; |
413
|
1
|
|
|
|
|
3
|
return ('ERROR', @_); |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
sub warn { |
417
|
0
|
|
|
0
|
0
|
|
my $self = shift(@_); |
418
|
0
|
|
|
|
|
|
$self->{n_warn}++; |
419
|
0
|
|
|
|
|
|
$self->{err} = $_[0]; |
420
|
0
|
|
|
|
|
|
$self->{err_ar} = \@_; |
421
|
0
|
|
|
|
|
|
return ('WARNING', @_); |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=head1 CAVEATS |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
This module works for the specific device shipped to the author, and might not work for you if Synaccess changes the behavior of their product. |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
The C can misbehave in odd ways if commands are sent to it too quickly or if connections are not terminated cleanly. The module uses short delays which helps mitigate some of these problems. (Despite these problems, the C is pretty good value for the price.) |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
=head1 TO DO |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
=over 4 |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
=item * Support commands for changing the C network configuration. |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=item * Improve the unit tests, which are a little shallow. |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=item * Support nonstandard port mapping. |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
=back |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
=head1 SEE ALSO |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
L - a light CLI utility wrapping this module. Not distributed with C to avoid spurious dependencies. |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
=head1 AUTHOR |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
TTK Ciar Ettk@ciar.orgE |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
=head1 COPYRIGHT |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
You may use and distribute this module under the same terms as Perl itself. |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
=cut |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
1; |