nutconnection.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. unit nutconnection;
  2. {
  3. $Id$
  4. This file is part of nutmon for netware
  5. Copyright (c) 2004 armin diehl ([email protected])
  6. Simple class to connect to the nut upsd, see
  7. http://www.networkupstools.org for details about the
  8. protocol
  9. Tested with nut 2.0.1pre4
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. **********************************************************************}
  14. {$mode objfpc}
  15. interface
  16. uses sysutils, ssockets;
  17. Const
  18. NutDefaultPort = 3493;
  19. NutLineEnd = #10;
  20. NutDataStale = 'ERR DATA-STALE';
  21. type
  22. TNutException = class (Exception);
  23. TUpsStat = (UPS_disconnected,UPS_stale,UPS_online,UPS_onBatt,UPS_lowBatt,UPS_FSD);
  24. TUpsStatus = set of TUpsStat;
  25. TNutConnection = class (TObject)
  26. private
  27. fSock : TInetSocket;
  28. fHost : string;
  29. fPort : word;
  30. fUpsName,fUserName,fPassword : string;
  31. fLogin : boolean;
  32. fDebug : boolean;
  33. fLastResponse : string;
  34. function isConnected : boolean;
  35. procedure doConnect (c : boolean);
  36. procedure setHost (s : string);
  37. procedure setPort (w : word);
  38. procedure sendCommand (s : string);
  39. function getOneLine : string;
  40. function getVersion : string;
  41. procedure setUpsName (s : string);
  42. procedure checkConnected;
  43. function getValue (name : string) : string;
  44. function getUpsLoad : string;
  45. function getUpsMfr : string;
  46. function getUpsModel : string;
  47. function getUpsRuntime : string;
  48. function getUpsCharge : string;
  49. function getUpsChargeInt : integer;
  50. function getUpsTemperature : string;
  51. function getInputFrequency : string;
  52. function getInputVoltage : string;
  53. function getOutputVoltage : string;
  54. function getUpsStatus : TUpsStatus;
  55. procedure setUserName (user : string);
  56. procedure setPassword (pwd : string);
  57. procedure doLogin (login : boolean);
  58. function getNumLogins : string;
  59. public
  60. property connected : boolean read isConnected write doConnect;
  61. property host : string read fHost write setHost;
  62. property port : word read fPort write setPort;
  63. property version : string read getVersion;
  64. property upsName : string read fUpsName write setUpsName;
  65. property upsload : string read getUpsLoad;
  66. property upsMfr : string read getUpsMfr;
  67. property upsModel : string read getUpsModel;
  68. property upsRuntime : string read getUpsRuntime;
  69. property upsCharge : string read getUpsCharge;
  70. property upsChargeInt : integer read getUpsChargeInt;
  71. property upsTemperature : string read getUpsTemperature;
  72. property upsInputFrequency : string read getInputFrequency;
  73. property upsInputVoltage : string read getInputVoltage;
  74. property upsOutputVoltage : string read getOutputVoltage;
  75. property upsStatus : TUpsStatus read getUpsStatus;
  76. property Username : string read fUsername write setUsername;
  77. property Password : string read fPassword write setPassword;
  78. // in case login is set to true (and username,password are ok)
  79. // upsd knows that this system gets power from the ups and
  80. // will switch off only after login was set to false
  81. property Login : boolean read fLogin write doLogin;
  82. property Debug : boolean read fDebug write fDebug;
  83. property LastResult : string read fLastResponse;
  84. property numLogins : string read getNumLogins;
  85. end;
  86. function UpsStatus2Txt (status : TUpsStatus) : string;
  87. implementation
  88. function TNutConnection.isConnected : boolean;
  89. begin
  90. result := (fSock <> nil);
  91. end;
  92. procedure TNutConnection.doConnect (c : boolean);
  93. begin
  94. if fSock <> nil then
  95. begin
  96. fSock.Free;
  97. fSock := nil;
  98. fLogin := false;
  99. end;
  100. if c then
  101. fSock := TInetSocket.Create (fHost, fPort);
  102. end;
  103. procedure TNutConnection.setHost (s : string);
  104. begin
  105. if fHost <> s then
  106. begin
  107. fHost := s;
  108. doConnect (isConnected);
  109. end;
  110. end;
  111. procedure TNutConnection.setPort (w : word);
  112. begin
  113. if w <> fPort then
  114. begin
  115. fPort := w;
  116. doConnect (isConnected);
  117. end;
  118. end;
  119. procedure TNutConnection.checkConnected;
  120. begin
  121. if not isConnected then
  122. raise (TNutException.Create ('not connected'));
  123. end;
  124. procedure TNutConnection.sendCommand (s : string);
  125. var len : longint;
  126. begin
  127. checkConnected;
  128. if fDebug then
  129. writeln (stderr,'S: "'+s+'"');
  130. s := s + NutLineEnd;
  131. len := fSock.Write (s[1],length(s));
  132. if (len <> length(s)) then
  133. begin
  134. if fDebug then
  135. writeln (stderr,'send error');
  136. doConnect (false);
  137. raise (TNutException.Create ('send failed, disconnected from upsd'));
  138. end;
  139. end;
  140. function TNutConnection.getOneLine : string;
  141. var c : char;
  142. begin
  143. checkConnected;
  144. fLastResponse := '';
  145. result := '';
  146. while (fSock.read (c,1) = 1) do
  147. begin
  148. if c = NutLineEnd then
  149. begin
  150. if fDebug then
  151. writeln (stderr,'R: "'+result+'"');
  152. fLastResponse := result;
  153. exit;
  154. end;
  155. result := result + c;
  156. end;
  157. end;
  158. function TNutConnection.getVersion : string;
  159. begin
  160. sendCommand ('VER');
  161. result := getOneLine;
  162. end;
  163. procedure TNutConnection.setUpsName (s : string);
  164. var res : string;
  165. begin
  166. fUpsName := '';
  167. sendCommand ('GET NUMLOGINS '+s);
  168. res := getOneLine;
  169. if copy (res,1,10) <> 'NUMLOGINS ' then
  170. Raise (TNutException.Create ('setUpsName, unknown response from upsd'));
  171. fUpsName := s;
  172. end;
  173. function TNutConnection.getValue (name : string) : string;
  174. var s : string;
  175. begin
  176. if fUpsName = '' then
  177. raise (TNutException.Create ('upsName not set'));
  178. sendCommand ('GET VAR '+fUpsName+' '+name);
  179. s := getOneLine;
  180. if s = 'ERR DATA-STALE' then
  181. begin
  182. result := s;
  183. exit;
  184. end;
  185. if copy (s,1,4) <> 'VAR ' then
  186. raise (TNutException.Create ('result from GET VAR invalid, does not begin with "VAR "'));
  187. delete (s,1,4);
  188. if ansiUpperCase (copy (s,1,length(fUpsName))) <> ansiUpperCase (fUpsName) then
  189. raise (TNutException.Create ('result from GET VAR invalid, second param was not upsName'));
  190. delete (s,1,length(fUpsName)+1);
  191. delete (s,1,length(name)+1);
  192. if copy (s,1,1) = '"' then delete (s,1,1);
  193. if copy (s,length(s),1) = '"' then delete (s,length(s),1);
  194. result := s;
  195. end;
  196. function TNutConnection.getUpsLoad : string;
  197. begin
  198. result := getValue ('ups.load');
  199. end;
  200. function TNutConnection.getUpsMfr : string;
  201. begin
  202. result := getValue ('ups.mfr');
  203. end;
  204. function TNutConnection.getUpsModel : string;
  205. begin
  206. result := getValue ('ups.model');
  207. end;
  208. function TNutConnection.getUpsRuntime : string;
  209. begin
  210. result := getValue ('battery.runtime');
  211. end;
  212. function TNutConnection.getUpsCharge : string;
  213. begin
  214. result := getValue ('battery.charge');
  215. end;
  216. function TNutConnection.getUpsChargeInt : integer;
  217. var s : string;
  218. p : integer;
  219. begin
  220. try
  221. s := getUpsCharge;
  222. p := Pos ('.',s);
  223. if p > 0 then
  224. delete (s,p,255);
  225. result := StrToInt (s);
  226. except
  227. result := 100;
  228. end;
  229. end;
  230. function TNutConnection.getUpsTemperature : string;
  231. begin
  232. result := getValue ('ups.temperature');
  233. end;
  234. function TNutConnection.getInputFrequency : string;
  235. begin
  236. result := getValue ('input.frequency');
  237. end;
  238. function TNutConnection.getInputVoltage : string;
  239. begin
  240. result := getValue ('input.voltage');
  241. end;
  242. function TNutConnection.getOutputVoltage : string;
  243. begin
  244. result := getValue ('output.voltage');
  245. end;
  246. function TNutConnection.getNumLogins : string;
  247. var res : string;
  248. p : integer;
  249. begin
  250. if fUpsName = '' then
  251. Raise (TNutException.Create ('getNumLogins, upsName not set'));
  252. sendCommand ('GET NUMLOGINS '+fUpsName);
  253. res := getOneLine;
  254. if copy (res,1,10) <> 'NUMLOGINS ' then
  255. Raise (TNutException.Create ('setUpsName, unknown response from upsd'));
  256. delete (res,1,10);
  257. p := pos (' ',res);
  258. if p > 0 then
  259. delete (res,1,p);
  260. result :=res;
  261. end;
  262. function TNutConnection.getUpsStatus : TUpsStatus;
  263. var s,value : string;
  264. i : integer;
  265. begin
  266. try
  267. s := getValue ('ups.status');
  268. result := [];
  269. if s = NutDataStale then
  270. result := [UPS_stale]
  271. else
  272. repeat
  273. i := pos (' ',s);
  274. if (i > 0) then
  275. begin
  276. value := trim(ansiuppercase(copy(s,1,i-1)));
  277. delete (s,1,i); s:=trim(s);
  278. end else
  279. begin
  280. value := trim(ansiuppercase(s));
  281. s := '';
  282. end;
  283. if value = 'OL' then
  284. result := result + [UPS_online]
  285. else if value = 'OB' then
  286. result := result + [UPS_onBatt]
  287. else if value = 'LB' then
  288. result := result + [UPS_LowBatt]
  289. else if value = 'FSD' then
  290. result := result + [UPS_FSD];
  291. until s = '';
  292. except
  293. result := [UPS_disconnected];
  294. end;
  295. end;
  296. procedure TNutConnection.setUserName (user : string);
  297. var res : string;
  298. begin
  299. fUserName := user;
  300. if fUserName <> '' then
  301. begin
  302. sendCommand ('USERNAME '+user);
  303. res := getOneLine;
  304. if res <> 'OK' then
  305. raise (TNutException.Create (format ('username failed (%s)',[res])));
  306. end;
  307. end;
  308. procedure TNutConnection.setPassword (pwd : string);
  309. var res : string;
  310. begin
  311. fPassword := pwd;
  312. if pwd <> '' then
  313. begin
  314. sendCommand ('PASSWORD '+pwd);
  315. res := getOneLine;
  316. if res <> 'OK' then
  317. raise (TNutException.Create (format ('password failed (%s)',[res])));
  318. end;
  319. end;
  320. procedure TNutConnection.doLogin (login : boolean);
  321. var res : string;
  322. begin
  323. if login then
  324. begin
  325. if fLogin then
  326. raise (TNutException.Create ('already logged in'));
  327. if (fUsername = '') or (fPassword = '') or (fUpsName = '') then
  328. raise (TNutException.Create ('Login requires UpsName, Username and Password'));
  329. sendCommand ('LOGIN '+fUpsName);
  330. res := getOneLine;
  331. if res <> 'OK' then
  332. raise (TNutException.Create (format ('login failed (%s)',[res])));
  333. fLogin := true;
  334. end else
  335. if fLogin then
  336. begin
  337. sendCommand ('LOGOUT');
  338. res := getOneLine;
  339. if (copy(res,1,2) <> 'OK') and (copy(res,1,6)<> 'Goodby') then
  340. raise (TNutException.Create (format('logout failed, got "%s"',[res])));
  341. fLogin := false;
  342. doConnect(false);
  343. end;
  344. end;
  345. function UpsStatus2Txt (status : TUpsStatus) : string;
  346. begin
  347. result := '';
  348. if UPS_disconnected in status then result := result + 'disconnected ';
  349. if UPS_stale in status then result := result + 'stale ';
  350. if UPS_online in status then result := result + 'online ';
  351. if UPS_onBatt in status then result := result + 'onBattery ';
  352. if UPS_lowBatt in status then result := result + 'LowBattery ';
  353. if UPS_FSD in status then result := result + 'ForeceShutdown ';
  354. result := trim(result);
  355. end;
  356. end.
  357. {
  358. $Log$
  359. Revision 1.1 2004-12-29 21:39:53 armin
  360. * changed makefile version to 1.9.6, added samples for Netware
  361. }