nutconnection.pp 10 KB

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