73_UpsPico.pm 79 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471
  1. # $Id: 73_UpsPico.pm 15394 2017-11-05 15:29:05Z Sailor $
  2. ########################################################################################################################
  3. #
  4. # 73_UpsPico.pm
  5. # Creates the possibility to access the UPS PIco Uninterrupteable Power Supply
  6. #
  7. # Author : Matthias Deeke
  8. # e-mail : matthias.deeke(AT)deeke(PUNKT)eu
  9. # Fhem Forum : https://forum.fhem.de/index.php/topic,77000.0.html
  10. # Fhem Wiki :
  11. #
  12. # This file is part of fhem.
  13. #
  14. # Fhem is free software: you can redistribute it and/or modify
  15. # it under the terms of the GNU General Public License as published by
  16. # the Free Software Foundation, either version 2 of the License, or
  17. # (at your option) any later version.
  18. #
  19. # Fhem is distributed in the hope that it will be useful,
  20. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. # GNU General Public License for more details.
  23. #
  24. # You should have received a copy of the GNU General Public License
  25. # along with fhem. If not, see <http://www.gnu.org/licenses/>.
  26. #
  27. # fhem.cfg: define <devicename> UpsPico <IPv4-address> <UpsOnPiUser> <UpsOnPiPassword>
  28. #
  29. # Example 1 - Bare Credentials:
  30. # define myUpsPico UpsPico 192.168.178.200 User Geheim
  31. #
  32. # Example 2 - base64 encoded Credentials: Both, username and password, may be pre-encode with base64 if attribute CredentialsEncrypted is set
  33. # define myUpsPico UpsPico 192.168.178.200 VXNlcm5hbWU= UGFzc3dvcmQ=
  34. #
  35. ########################################################################################################################
  36. ########################################################################################################################
  37. # List of open Problems:
  38. #
  39. # Set - command not yet implemented
  40. #
  41. ########################################################################################################################
  42. package main;
  43. use strict;
  44. use warnings;
  45. use Net::OpenSSH;
  46. use Data::Dumper qw(Dumper);
  47. use Math::Expression::Evaluator;
  48. use Digest::MD5 qw(md5 md5_hex md5_base64);
  49. use constant false => 0;
  50. use constant true => 1;
  51. sub UpsPico_Attr(@);
  52. sub UpsPico_Get($@);
  53. sub UpsPico_Set($@);
  54. sub UpsPico_Define($$);
  55. sub UpsPico_Undefine($$);
  56. sub UpsPico_Initialize($);
  57. sub UpsPico_GetAllData($@);
  58. sub UpsPico_DbLog_splitFn($$);
  59. sub UpsPico_CheckConnection($@);
  60. ###START###### Initialize module ##############################################################################START####
  61. sub UpsPico_Initialize($)
  62. {
  63. my ($hash) = @_;
  64. $hash->{STATE} = "Init";
  65. $hash->{DefFn} = "UpsPico_Define";
  66. $hash->{UndefFn} = "UpsPico_Undefine";
  67. $hash->{SetFn} = "UpsPico_Set";
  68. $hash->{GetFn} = "UpsPico_Get";
  69. $hash->{AttrFn} = "UpsPico_Attr";
  70. $hash->{DbLog_splitFn} = "UpsPico_DbLog_splitFn";
  71. $hash->{AttrList} = "do_not_notify:0,1 " .
  72. "header " .
  73. "Port " .
  74. "WriteCritical:0,1 " .
  75. "disable:1,0 " .
  76. "loglevel:0,1,2,3,4,5 " .
  77. "PollingInterval " .
  78. "CredentialsEncrypted:0,1 " .
  79. $readingFnAttributes;
  80. }
  81. ####END####### Initialize module ###############################################################################END#####
  82. ###START###### Activate module after module has been used via fhem command "define" ##########################START####
  83. sub UpsPico_Define($$)
  84. {
  85. my ($hash, $def) = @_;
  86. my @a = split("[ \t][ \t]*", $def);
  87. my $name = $a[0];
  88. #$a[1] just contains the "UpsPico" module name and we already know that! :-)
  89. my $url = $a[2];
  90. my $RemotePiUser = $a[3];
  91. my $RemotePiPass = $a[4];
  92. $hash->{NAME} = $name;
  93. $hash->{STATE} = "define";
  94. Log3 $name, 4, $name. " : UpsPico_Define - Starting to define module";
  95. ###START###### Reset fullResponse error message ############################################################START####
  96. readingsSingleUpdate( $hash, "fullResponse", "Initialising...", 1);
  97. ####END####### Reset fullResponse error message #############################################################END#####
  98. ### Stop the current timer if one exists errornous
  99. RemoveInternalTimer($hash);
  100. Log3 $name, 4, $name. " : UpsPico_Define - InternalTimer has been removed.";
  101. ###START### Check whether all variables are available #####################################################START####
  102. if (int(@a) == 5)
  103. {
  104. ###START### Check whether IPv4 address is valid
  105. if ($url =~ m/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/)
  106. {
  107. Log3 $name, 4, $name. " : UpsPico_Define - IPv4-address is valid : " . $url;
  108. }
  109. else
  110. {
  111. return $name .": Error - IPv4 address is not valid \n Please use \"define <devicename> UpsPico <IPv4-address> <interval/[s]> <Username> <Password>\" instead";
  112. }
  113. ####END#### Check whether IPv4 address is valid
  114. }
  115. else
  116. {
  117. return $name .": UpsPico - Error - Not enough or too much parameter provided." . "\n" . "Gateway IPv4 address, Username and Password must be provided" ."\n". "Please use \"define <devicename> UpsPico <IPv4-address> <Username> <Password>\" instead";
  118. }
  119. ####END#### Check whether all variables are available ######################################################END#####
  120. ###START### Decode Username and Password if base 64 coded #################################################START####
  121. if (defined($attr{$name}{CredentialsEncrypted}))
  122. {
  123. if ($attr{$name}{CredentialsEncrypted} == 1)
  124. {
  125. $RemotePiUser = decode_base64($RemotePiUser);
  126. $RemotePiPass = decode_base64($RemotePiPass);
  127. }
  128. }
  129. ####END#### Decode Username and Password if base 64 coded ##################################################END#####
  130. ###START###### Provide basic Information for all register #################################################START####
  131. my %RegisterInfo;
  132. $RegisterInfo{"mode"} = {RegisterBlockName => "Status", RegisterAddress => 0x00, DataType => "Byte", Writeable => false, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => {0x01 => "RPI_MODE", 0x02 => "BAT_MODE", Default => "ERROR"} };
  133. $RegisterInfo{"batlevel"} = {RegisterBlockName => "Status", RegisterAddress => 0x08, DataType => "WordBCD", Writeable => false, Reset => false, Critical => false, Factor => 0.01, Unit => "V", SelectionList => undef };
  134. $RegisterInfo{"rpilevel"} = {RegisterBlockName => "Status", RegisterAddress => 0x0a, DataType => "WordBCD", Writeable => false, Reset => false, Critical => false, Factor => 0.01, Unit => "V", SelectionList => undef };
  135. $RegisterInfo{"eprlevel"} = {RegisterBlockName => "Status", RegisterAddress => 0x0c, DataType => "WordBCD", Writeable => false, Reset => false, Critical => false, Factor => 0.01, Unit => "V", SelectionList => undef };
  136. $RegisterInfo{"aEXT0level"} = {RegisterBlockName => "Status", RegisterAddress => 0x14, DataType => "WordBCD", Writeable => false, Reset => false, Critical => false, Factor => 0.01, Unit => "V", SelectionList => undef };
  137. $RegisterInfo{"aEXT1level"} = {RegisterBlockName => "Status", RegisterAddress => 0x16, DataType => "WordBCD", Writeable => false, Reset => false, Critical => false, Factor => 0.01, Unit => "V", SelectionList => undef };
  138. $RegisterInfo{"aEXT2level"} = {RegisterBlockName => "Status", RegisterAddress => 0x18, DataType => "WordBCD", Writeable => false, Reset => false, Critical => false, Factor => 0.01, Unit => "V", SelectionList => undef };
  139. $RegisterInfo{"key"} = {RegisterBlockName => "Status", RegisterAddress => 0x1a, DataType => "Byte", Writeable => true, Reset => true, Critical => false, Factor => undef, Unit => undef, SelectionList => {0x00 => "No Key pressed", 0x01 => "Key A pressed", 0x02 => "Key B pressed", 0x03 => "Key C pressed", Default => "ERROR"} };
  140. $RegisterInfo{"ntc"} = {RegisterBlockName => "Status", RegisterAddress => 0x1b, DataType => "Byte", Writeable => false, Reset => false, Critical => false, Factor => 1.00, Unit => "&deg;C", SelectionList => undef };
  141. $RegisterInfo{"TO92"} = {RegisterBlockName => "Status", RegisterAddress => 0x1c, DataType => "Byte", Writeable => false, Reset => false, Critical => false, Factor => 1.00, Unit => "&deg;C", SelectionList => undef };
  142. $RegisterInfo{"charger"} = {RegisterBlockName => "Status", RegisterAddress => 0x20, DataType => "Byte", Writeable => false, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => {0x00 => "Charger OFF", 0x01 => "Charging Batt", Default => "ERROR"} };
  143. $RegisterInfo{"pico_is_running"} = {RegisterBlockName => "Status", RegisterAddress => 0x22, DataType => "WordHex", Writeable => false, Reset => false, Critical => false, Factor => 1.00, Unit => "ms", SelectionList => undef };
  144. $RegisterInfo{"pv"} = {RegisterBlockName => "Status", RegisterAddress => 0x24, DataType => "ASCII", Writeable => false, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => undef };
  145. $RegisterInfo{"bv"} = {RegisterBlockName => "Status", RegisterAddress => 0x25, DataType => "ASCII", Writeable => false, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => undef };
  146. $RegisterInfo{"fv"} = {RegisterBlockName => "Status", RegisterAddress => 0x26, DataType => "Byte", Writeable => false, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => undef };
  147. $RegisterInfo{"RTC_seconds"} = {RegisterBlockName => "RTC", RegisterAddress => 0x00, DataType => "Byte", Writeable => false, Reset => false, Critical => false, Factor => 1.00, Unit => "s", SelectionList => undef };
  148. $RegisterInfo{"RTC_minutes"} = {RegisterBlockName => "RTC", RegisterAddress => 0x01, DataType => "Byte", Writeable => false, Reset => false, Critical => false, Factor => 1.00, Unit => "min", SelectionList => undef };
  149. $RegisterInfo{"RTC_hours"} = {RegisterBlockName => "RTC", RegisterAddress => 0x02, DataType => "Byte", Writeable => false, Reset => false, Critical => false, Factor => 1.00, Unit => "h", SelectionList => undef };
  150. $RegisterInfo{"RTC_wday"} = {RegisterBlockName => "RTC", RegisterAddress => 0x03, DataType => "Byte", Writeable => false, Reset => false, Critical => false, Factor => 1.00, Unit => " ", SelectionList => undef };
  151. $RegisterInfo{"RTC_mday"} = {RegisterBlockName => "RTC", RegisterAddress => 0x04, DataType => "Byte", Writeable => false, Reset => false, Critical => false, Factor => 1.00, Unit => " ", SelectionList => undef };
  152. $RegisterInfo{"RTC_month"} = {RegisterBlockName => "RTC", RegisterAddress => 0x05, DataType => "Byte", Writeable => false, Reset => false, Critical => false, Factor => 1.00, Unit => " ", SelectionList => undef };
  153. $RegisterInfo{"RTC_year"} = {RegisterBlockName => "RTC", RegisterAddress => 0x06, DataType => "Byte", Writeable => false, Reset => false, Critical => false, Factor => 1.00, Unit => " ", SelectionList => undef };
  154. $RegisterInfo{"pico_state"} = {RegisterBlockName => "Command", RegisterAddress => 0x00, DataType => "Byte", Writeable => true, Reset => false, Critical => true, Factor => undef, Unit => undef, SelectionList => {0x00 => "OK", 0x80 => "OK", 0xcc => "Shutdown", 0xdd => "Factory Reset", 0xee => "CPU Reset", 0xff => "Bootloader", 0xa0 => "DEFAULT", 0xa1 => "NO_RTC", 0xa2 => "ALTERNATE", Default => "ERROR"}};
  155. $RegisterInfo{"bat_run_time"} = {RegisterBlockName => "Command", RegisterAddress => 0x01, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => 1.00, Unit => "s", SelectionList => {0xff => "BattLive", Default => "Function: 60+RegisterValue*60"} };
  156. $RegisterInfo{"rs232_rate"} = {RegisterBlockName => "Command", RegisterAddress => 0x02, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => {0x00 => "Disabled", 0x01 => "4800bps", 0x02 => "9600bps", 0x03 => "19200bps", 0x04 => "34600bps", 0x05 => "57600bps", 0x0f => "115200bps",Default => "ERROR"} };
  157. $RegisterInfo{"STA_timer"} = {RegisterBlockName => "Command", RegisterAddress => 0x05, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => 1.00, Unit => "s", SelectionList => {0xff => "Disabled", Default => "Function: RegisterValue"} };
  158. $RegisterInfo{"enable5V"} = {RegisterBlockName => "Command", RegisterAddress => 0x06, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => {0x00 => "Disabled", 0x01 => "Enabled", Default => "ERROR"} };
  159. $RegisterInfo{"battype"} = {RegisterBlockName => "Command", RegisterAddress => 0x07, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => {0x46 => "LiFePO4 - F", 0x51 => "LiFePO4 - Q", 0x53 => "LiPO - S", 0x50 => "LiPO - P", Default => "ERROR"} };
  160. $RegisterInfo{"setA_D"} = {RegisterBlockName => "Command", RegisterAddress => 0x08, DataType => "Byte", Writeable => true, Reset => false, Critical => true, Factor => undef, Unit => undef, SelectionList => {0x00 => "AEXT1: 05.2V; AEXT2: 05.2V;", 0x01 => "AEXT1: 05.2V; AEXT2: 10.0V;", 0x02 => "AEXT1: 05.2V; AEXT2: 20.0V;", 0x03 => "AEXT1: 05.2V; AEXT2: 30.0V;", 0x10 => "AEXT1: 10.0V; AEXT2: 05.2V;", 0x11 => "AEXT1: 10.0V; AEXT2: 10.0V;", 0x12 => "AEXT1: 10.0V; AEXT2: 20.0V;", 0x13 => "AEXT1: 10.0V; AEXT2: 30.0V;", 0x20 => "AEXT1: 20.0V; AEXT2: 05.2V;", 0x21 => "AEXT1: 20.0V; AEXT2: 10.0V;", 0x22 => "AEXT1: 20.0V; AEXT2: 20.0V;", 0x23 => "AEXT1: 20.0V; AEXT2: 30.0V;", 0x30 => "AEXT1: 30.0V; AEXT2: 05.2V;", 0x31 => "AEXT1: 30.0V; AEXT2: 10.0V;", 0x32 => "AEXT1: 30.0V; AEXT2: 20.0V;", 0x33 => "AEXT1: 30.0V; AEXT2: 30.0V;", Default => "ERROR"} };
  161. $RegisterInfo{"User_LED_Orange"} = {RegisterBlockName => "Command", RegisterAddress => 0x09, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => {0x00 => "OFF", 0x01 => "ON", Default => "ERROR"} };
  162. $RegisterInfo{"User_LED_Green"} = {RegisterBlockName => "Command", RegisterAddress => 0x0a, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => {0x00 => "OFF", 0x01 => "ON", Default => "ERROR"} };
  163. $RegisterInfo{"User_LED_Blue"} = {RegisterBlockName => "Command", RegisterAddress => 0x0b, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => {0x00 => "OFF", 0x01 => "ON", Default => "ERROR"} };
  164. $RegisterInfo{"brelay"} = {RegisterBlockName => "Command", RegisterAddress => 0x0c, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => {0x00 => "Reset", 0x01 => "Set", Default => "ERROR"} };
  165. $RegisterInfo{"bmode"} = {RegisterBlockName => "Command", RegisterAddress => 0x0d, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => {0x00 => "Disabled", 0x01 => "Enabled", Default => "ERROR"} };
  166. $RegisterInfo{"bfreq"} = {RegisterBlockName => "Command", RegisterAddress => 0x0e, DataType => "WordBCD", Writeable => true, Reset => false, Critical => false, Factor => 1.00, Unit => "Hz", SelectionList => undef };
  167. $RegisterInfo{"bdur"} = {RegisterBlockName => "Command", RegisterAddress => 0x10, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => 10, Unit => "ms", SelectionList => undef };
  168. $RegisterInfo{"fmode"} = {RegisterBlockName => "Command", RegisterAddress => 0x11, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => {0x00 => "Disabled", 0x01 => "Enabled", 0x02 => "Auto", Default => "ERROR"} };
  169. $RegisterInfo{"fspeed"} = {RegisterBlockName => "Command", RegisterAddress => 0x12, DataType => "Hex", Writeable => true, Reset => false, Critical => false, Factor => 1.00, Unit => "%", SelectionList => undef };
  170. $RegisterInfo{"fstat"} = {RegisterBlockName => "Command", RegisterAddress => 0x13, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => {0x00 => "OFF", 0x01 => "ON", Default => "ERROR"} };
  171. $RegisterInfo{"fttemp"} = {RegisterBlockName => "Command", RegisterAddress => 0x14, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => 1.00, Unit => "&deg;C", SelectionList => undef };
  172. $RegisterInfo{"LED_OFF"} = {RegisterBlockName => "Command", RegisterAddress => 0x15, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => {0x00 => "All LEDs forced OFF", 0x01 => "All LED manual", Default => "ERROR"} };
  173. $RegisterInfo{"STS_active"} = {RegisterBlockName => "StartTS", RegisterAddress => 0x00, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => {0x00 => "Inactive", 0xff => "Active", Default => "ERROR"} };
  174. $RegisterInfo{"STS_minute"} = {RegisterBlockName => "StartTS", RegisterAddress => 0x01, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => 1.00, Unit => "min", SelectionList => undef };
  175. $RegisterInfo{"STS_hour"} = {RegisterBlockName => "StartTS", RegisterAddress => 0x02, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => 1.00, Unit => "h", SelectionList => undef };
  176. $RegisterInfo{"STS_mday"} = {RegisterBlockName => "StartTS", RegisterAddress => 0x03, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => 1.00, Unit => "d", SelectionList => undef };
  177. $RegisterInfo{"STS_month"} = {RegisterBlockName => "StartTS", RegisterAddress => 0x04, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => 1.00, Unit => "m", SelectionList => undef };
  178. $RegisterInfo{"STS_year"} = {RegisterBlockName => "StartTS", RegisterAddress => 0x05, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => 1.00, Unit => "y", SelectionList => undef };
  179. $RegisterInfo{"D_repetition"} = {RegisterBlockName => "RunTS", RegisterAddress => 0x00, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => 1.00, Unit => "d", SelectionList => {0xff => "Disabled", Default => "Function: RegisterValue"} };
  180. $RegisterInfo{"H_repetition"} = {RegisterBlockName => "RunTS", RegisterAddress => 0x01, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => 1.00, Unit => "h", SelectionList => {0xff => "Disabled", Default => "Function: RegisterValue"} };
  181. $RegisterInfo{"M_repetition"} = {RegisterBlockName => "RunTS", RegisterAddress => 0x02, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => 1.00, Unit => "min", SelectionList => {0xff => "Disabled", Default => "Function: RegisterValue"} };
  182. $RegisterInfo{"H_duration"} = {RegisterBlockName => "RunTS", RegisterAddress => 0x03, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => 1.00, Unit => "h", SelectionList => {0xff => "Disabled", Default => "Function: RegisterValue"} };
  183. $RegisterInfo{"M_duration"} = {RegisterBlockName => "RunTS", RegisterAddress => 0x04, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => 1.00, Unit => "min", SelectionList => {0xff => "Disabled", Default => "Function: RegisterValue"} };
  184. # $RegisterInfo{"??????????"} = {RegisterBlockName => "EventS", RegisterAddress => 0x00, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => undef };
  185. # $RegisterInfo{"??????????"} = {RegisterBlockName => "ActionS", RegisterAddress => 0x00, DataType => "Byte", Writeable => true, Reset => false, Critical => false, Factor => undef, Unit => undef, SelectionList => undef };
  186. ####END####### Provide basic Information for all register ##################################################END#####
  187. ###START###### Provide charging information for batteries #################################################START####
  188. my %BattChargingInfo;
  189. $BattChargingInfo{"LiFePO4 - F"} = {Volt0Percent => 2.9, Volt100Percent => 3.6};
  190. $BattChargingInfo{"LiFePO4 - Q"} = {Volt0Percent => 2.9, Volt100Percent => 3.6};
  191. $BattChargingInfo{"LiPO - S"} = {Volt0Percent => 3.4, Volt100Percent => 4.3};
  192. $BattChargingInfo{"LiPO - P"} = {Volt0Percent => 3.4, Volt100Percent => 4.3};
  193. ####END####### Provide charging information for batteries ##################################################END#####
  194. ###START###### Writing values to global hash ##############################################################START####
  195. $hash->{NAME} = $name;
  196. $hash->{URL} = $url;
  197. $hash->{temp}{FIRSTTIME} = true;
  198. $hash->{temp}{RemotePiUser} = $RemotePiUser;
  199. $hash->{temp}{RemotePiPass} = $RemotePiPass;
  200. %{$hash->{temp}{RegisterInfo}} = %RegisterInfo;
  201. %{$hash->{temp}{BattChargingInfo}} = %BattChargingInfo;
  202. ####END####### Writing values to global hash ###############################################################END#####
  203. ###START###### For Debugging purpose only #################################################################START####
  204. Log3 $name, 4, $name. " : UpsPico_Define Hash : " . $hash;
  205. Log3 $name, 4, $name. " : UpsPico_Define Def : " . $def;
  206. Log3 $name, 4, $name. " : UpsPico_Define Array : " . @a;
  207. Log3 $name, 4, $name. " : UpsPico_Define Name : " . $name;
  208. Log3 $name, 4, $name. " : UpsPico_Define Address : " . $url;
  209. Log3 $name, 5, $name. " : UpsPico -----------------------------------------------------------------------------";
  210. Log3 $name, 5, $name. " : UpsPico - RegisterInfo in fhem-hash : \n" . Dumper \%$hash;
  211. Log3 $name, 5, $name. " : UpsPico -----------------------------------------------------------------------------";
  212. ####END####### For Debugging purpose only ##################################################################END#####
  213. ###Initiate the timer for first check of connection towards RasPi with UpsPico but wait 30s
  214. InternalTimer(gettimeofday()+30, "UpsPico_CheckConnection", $hash, 0);
  215. return undef;
  216. }
  217. ####END####### Activate module after module has been used via fhem command "define" ############################END#####
  218. ###START###### To bind unit of value to DbLog entries #########################################################START####
  219. sub UpsPico_DbLog_splitFn($$)
  220. {
  221. my ($event, $name) = @_;
  222. my $hash = $defs{$name};
  223. my %RegisterInfo = %{$hash->{temp}{RegisterInfo}};
  224. my @argument = split("[ \t][ \t]*", $event);
  225. #### Delete ":" and everything behind in readings name
  226. $argument[0] =~ s/:.*//;
  227. ### Pre-Define variables
  228. my $reading = $argument[0];
  229. my $value = $argument[1];
  230. my $unit = undef;
  231. ### Log entries for debugging
  232. Log3 $name, 5, $name. " : UpsPico_DbLog_splitFn - Content of event : " . $event;
  233. Log3 $name, 5, $name. " : UpsPico_DbLog_splitFn - Content of argument[0] : " . $argument[0];
  234. Log3 $name, 5, $name. " : UpsPico_DbLog_splitFn - Content of argument[1] : " . $argument[1];
  235. ### Split Reading in RegisterI2CBlock and RegisterName
  236. my @SplitRegisterReading = split(/\//,$argument[0]);
  237. # $SplitRegisterReading[0] is an empty field
  238. my $RegisterI2CBlockNameEvent = $SplitRegisterReading[1];
  239. my $RegisterNameEvent = $SplitRegisterReading[2];
  240. Log3 $name, 5, $name. " : UpsPico_DbLog_splitFn - Content of RegisterI2CBlockNameEvent : " . $RegisterI2CBlockNameEvent;
  241. Log3 $name, 5, $name. " : UpsPico_DbLog_splitFn - Content of RegisterNameEvent : " . $RegisterNameEvent;
  242. ### Set I2CBlockAddressnames
  243. my %I2CAddress;
  244. $I2CAddress{Status} = undef;
  245. $I2CAddress{RTC} = undef;
  246. $I2CAddress{Command} = undef;
  247. $I2CAddress{StartTS} = undef;
  248. $I2CAddress{RunTS} = undef;
  249. $I2CAddress{EventS} = undef;
  250. $I2CAddress{ActionS} = undef;
  251. ### For all specified RegisterI2CBlocks and registers: Search for unit
  252. SearchLoop:
  253. {
  254. foreach my $RegisterI2CBlock (keys %I2CAddress)
  255. {
  256. ### If the RegisterI2CBlock to be changed is identical to the RegisterI2CBlock in the loop
  257. if ($RegisterI2CBlockNameEvent eq $RegisterI2CBlock)
  258. {
  259. ### For all specified Register
  260. foreach my $RegisterName (keys %RegisterInfo)
  261. {
  262. ### If the RegisterName to be changed is identical to the RegisterName in the loop
  263. if ($RegisterNameEvent eq $RegisterName)
  264. {
  265. Log3 $name, 5, $name. " : UpsPico_DbLog_splitFn - Found Register for reading : " . $reading;
  266. ### Extract value and unit
  267. $unit = $RegisterInfo{$RegisterName}{Unit};
  268. last SearchLoop;
  269. }
  270. }
  271. }
  272. }
  273. }
  274. ### Log entries for debugging
  275. Log3 $name, 5, $name. " : UpsPico_DbLog_splitFn - Content of reading : " . $reading;
  276. Log3 $name, 5, $name. " : UpsPico_DbLog_splitFn - Content of value : " . $value;
  277. Log3 $name, 5, $name. " : UpsPico_DbLog_splitFn - Content of unit : " . $unit;
  278. return ($reading, $value, $unit);
  279. }
  280. ####END####### To bind unit of value to DbLog entries ##########################################################END#####
  281. ###START###### Deactivate module module after "undefine" command by fhem ######################################START####
  282. sub UpsPico_Undefine($$)
  283. {
  284. my ($hash, $def) = @_;
  285. my $name = $hash->{NAME};
  286. my $url = $hash->{URL};
  287. ### Stop the internal timer for this module
  288. RemoveInternalTimer($hash);
  289. Log3 $name, 3, $name. " - UpsPico has been undefined. The KM unit at $url will no longer polled.";
  290. return undef;
  291. }
  292. ####END####### Deactivate module module after "undefine" command by fhem #######################################END#####
  293. ###START###### Handle attributes after changes via fhem GUI ###################################################START####
  294. sub UpsPico_Attr(@)
  295. {
  296. my @a = @_;
  297. my $name = $a[1];
  298. my $hash = $defs{$name};
  299. ### Check whether disable attribute has been provided
  300. if ($a[2] eq "disable")
  301. {
  302. ###START### Check whether device shall be disabled
  303. if ($a[3] == 1)
  304. {
  305. ### Set new status
  306. $hash->{STATE} = "Disabled";
  307. ### Stop the current timer
  308. RemoveInternalTimer($hash);
  309. Log3 $name, 4, $name. " : UpsPico_Attr - InternalTimer has been removed.";
  310. ### Delete all Readings
  311. fhem( "deletereading $name .*" );
  312. Log3 $name, 3, $name. " : UpsPico_Attr - Device disabled as per attribute.";
  313. }
  314. else
  315. {
  316. ### Initiate the timer for first time polling of values from UpsPico but wait 10s
  317. $hash->{temp}{FIRSTTIME} = true;
  318. RemoveInternalTimer($hash);
  319. InternalTimer(gettimeofday()+180, "UpsPico_CheckConnection", $hash, 0);
  320. Log3 $name, 4, $name. " : UpsPico_Attr - Internal timer for Initialisation of services re-started.";
  321. Log3 $name, 4, $name. " : UpsPico_Attr - Device enabled as per attribute.";
  322. }
  323. ####END#### Check whether device shall be disabled
  324. }
  325. ### Check whether polling interval attribute for all data has been provided
  326. elsif ($a[2] eq "PollingInterval")
  327. {
  328. my $PollingInterval = $a[3];
  329. ###START### Check whether polling interval is not too short
  330. if ($PollingInterval > 19)
  331. {
  332. ### Initiate the timer for first time polling of values from UpsPico but wait 10s
  333. $hash->{temp}{FIRSTTIME} = true;
  334. RemoveInternalTimer($hash);
  335. InternalTimer(gettimeofday()+180, "UpsPico_CheckConnection", $hash, 0);
  336. Log3 $name, 4, $name. " : UpsPico_Attr - Interval for all data set to attribute value :" . $PollingInterval ." s";
  337. Log3 $name, 4, $name. " : UpsPico_Attr - Internal timer for Initialisation of services re-started.";
  338. }
  339. else
  340. {
  341. return $name .": Error - Polling interval too small - server response time greater than defined interval, please use something >=20, default is 90";
  342. }
  343. ####END#### Check whether polling interval is not too short
  344. }
  345. ### If no attributes of the above mentioned ones have been selected
  346. else
  347. {
  348. # Do nothing
  349. }
  350. return undef;
  351. }
  352. ####END####### Handle attributes after changes via fhem GUI ####################################################END#####
  353. ###START###### Obtain value after "get" command by fhem #######################################################START####
  354. sub UpsPico_Get($@)
  355. {
  356. my ( $hash, @a ) = @_;
  357. ### If not enough arguments have been provided
  358. if ( @a < 2 )
  359. {
  360. return "\"UpsPico_Get\" needs at least one argument";
  361. }
  362. my $name = shift @a;
  363. my $reading = shift @a;
  364. my $host = $hash->{URL};
  365. my $user = $hash->{temp}{RemotePiUser};
  366. my $pass = $hash->{temp}{RemotePiPass};
  367. my %RegisterInfo = %{$hash->{temp}{RegisterInfo}};
  368. ### Pre-Define variables
  369. my $ReturnMessage;
  370. ### Log entries for debugging
  371. Log3 $name, 5, $name. " : UpsPico_Get ------------------- Definition ----------------------------------------------";
  372. Log3 $name, 5, $name. " : UpsPico_Get - name : " . $name;
  373. Log3 $name, 5, $name. " : UpsPico_Get - reading : " . $reading;
  374. ### Prepare list of readings to be selected
  375. if(!$hash->{READINGS}{$reading})
  376. {
  377. my @cList = sort keys %{$hash->{READINGS}};
  378. return "Unknown argument $reading, choose one of " . join(" ", @cList);
  379. }
  380. ### Split Reading in RegisterI2CBlock and RegisterName
  381. my @SplitRegisterReading = split(/\//,$reading);
  382. # $SplitRegisterReading[0] is an empty field
  383. my $RegisterI2CBlockNameEvent = $SplitRegisterReading[1];
  384. my $RegisterNameEvent = $SplitRegisterReading[2];
  385. Log3 $name, 5, $name. " : UpsPico_Get - Content of RegisterI2CBlockNameEvent : " . $RegisterI2CBlockNameEvent;
  386. Log3 $name, 5, $name. " : UpsPico_Get - Content of RegisterNameEvent : " . $RegisterNameEvent;
  387. ### Set I2C address block hash
  388. my %I2CAddress;
  389. $I2CAddress{Status} = undef;
  390. $I2CAddress{RTC} = undef;
  391. $I2CAddress{Command} = undef;
  392. $I2CAddress{StartTS} = undef;
  393. $I2CAddress{RunTS} = undef;
  394. $I2CAddress{EventS} = undef;
  395. $I2CAddress{ActionS} = undef;
  396. ### For all specified RegisterI2CBlocks and registers: Search for unit and register address
  397. SearchLoop:
  398. {
  399. foreach my $RegisterI2CBlock (keys %I2CAddress)
  400. {
  401. ### If the RegisterI2CBlock to be changed is identical to the RegisterI2CBlock in the loop
  402. if ($RegisterI2CBlockNameEvent eq $RegisterI2CBlock)
  403. {
  404. ### For all specified Register
  405. foreach my $RegisterName (keys %RegisterInfo)
  406. {
  407. ### If the RegisterName to be changed is identical to the RegisterName in the loop
  408. if ($RegisterNameEvent eq $RegisterName)
  409. {
  410. Log3 $name, 5, $name. " : UpsPico_Get - Found Register for reading : " . $reading;
  411. ### Call Download
  412. UpsPico_GetAllData($hash, @a);
  413. ### Log entries for debugging
  414. Log3 $name, 5, $name. " : UpsPico_Get ------------------- Final Handover ------------------------------------------";
  415. Log3 $name, 5, $name. " : UpsPico_Get - reading : " . $reading;
  416. Log3 $name, 5, $name. " : UpsPico_Get - RegisterName : " . $RegisterName;
  417. Log3 $name, 5, $name. " : UpsPico_Get - RegisterInfo{RegisterName}{Value} : " . $RegisterInfo{$RegisterName}{Value};
  418. Log3 $name, 5, $name. " : UpsPico_Get - RegisterInfo{RegisterName}{Unit} : " . $RegisterInfo{$RegisterName}{Unit};
  419. Log3 $name, 5, $name. " : UpsPico_Get ==============================================================================";
  420. ### Prepare the message
  421. $ReturnMessage = $reading . " = " . $RegisterInfo{$RegisterName}{Value} . " " . $RegisterInfo{$RegisterName}{Unit};
  422. ### Break the loop since the job is done
  423. last SearchLoop;
  424. }
  425. }
  426. }
  427. }
  428. }
  429. ### Return value
  430. return($ReturnMessage);
  431. }
  432. ####END####### Obtain value after "get" command by fhem ########################################################END#####
  433. ###START###### Manipulate service after "set" command by fhem #################################################START####
  434. sub UpsPico_Set($@)
  435. {
  436. my ( $hash, @a ) = @_;
  437. ### If not enough arguments have been provided
  438. if ( @a < 2 )
  439. {
  440. return "\"set UpsPico\" needs at least one argument";
  441. }
  442. my $name = shift @a;
  443. my $register = shift @a;
  444. my $value = join(" ", @a);
  445. my %UpsPico_sets;
  446. my $ReturnMessage;
  447. return($ReturnMessage);
  448. ### DO NOT FORGET TO CHECK ATTRIBUTE "WriteCritical"!!!
  449. ### DO NOT FORGET TO RESET ATTRIBUTE "WriteCritical" after every single reading!!! Use fhem command "save"
  450. }
  451. ####END####### Manipulate service after "Set" command by fhem ##################################################END#####
  452. ###START###### Check connection towards remote RasPi via SSH ##################################################START####
  453. sub UpsPico_CheckConnection($@)
  454. {
  455. my ($hash, $def) = @_;
  456. my $name = $hash->{NAME};
  457. my $url = $hash->{URL};
  458. Log3 $name, 5, $name. " : UpsPico - CheckConnection-------------------------------------------------------------------------------------------------";
  459. ### Stop the internal timer for this module
  460. RemoveInternalTimer($hash);
  461. Log3 $name, 4, $name. " : UpsPico - CheckConnection - Internal Timer has been removed";
  462. ###START###### Try to access UpsPIco to get I2C address range ##############################################START####
  463. my $port = $attr{$name}{Port};
  464. my $stderr = 0;
  465. my $RemotePiUser = $hash->{temp}{RemotePiUser};
  466. my $RemotePiPass = $hash->{temp}{RemotePiPass};
  467. my $stdout;
  468. my $exit;
  469. my $cmd;
  470. my $ssh;
  471. ###START###### Reset fullResponse error message ############################################################START####
  472. readingsSingleUpdate( $hash, "fullResponse", "Checking Connection...", 1);
  473. ####END####### Reset fullResponse error message #############################################################END#####
  474. eval {$ssh = Net::SSH::Perl->new($url);};
  475. if( $@ )
  476. {
  477. ###Set warning for log file
  478. Log3 $name, 1, $name. " : UpsPico - CheckConnection - SSH Connection to RasPi with UPS-PIco could not be established since network connection failed. Retrying in 300s";
  479. ### Stop the internal timer for this module and re-initiate the timer for another check of connection towards RasPi with UpsPico but wait 300s
  480. RemoveInternalTimer($hash);
  481. $hash->{temp}{FIRSTTIME} = true;
  482. InternalTimer(gettimeofday()+30, "UpsPico_CheckConnection", $hash, 0);
  483. Log3 $name, 4, $name. " : UpsPico - CheckConnection - Internal Timer has been removed and restarted to check connection again in 300s";
  484. undef $ssh;
  485. return undef;
  486. }
  487. else
  488. {
  489. eval {$ssh->login($RemotePiUser, $RemotePiPass);};
  490. if( $@ )
  491. {
  492. ###Set warning for log file
  493. Log3 $name, 1, $name. " : UpsPico - CheckConnection - SSH Login to RasPi with UPS-PIco could not be established due to wrong credentials. Retrying in 300s";
  494. ### Stop the internal timer for this module and re-initiate the timer for another check of connection towards RasPi with UpsPico but wait 10s
  495. RemoveInternalTimer($hash);
  496. $hash->{temp}{FIRSTTIME} = true;
  497. InternalTimer(gettimeofday()+30, "UpsPico_CheckConnection", $hash, 0);
  498. Log3 $name, 4, $name. " : UpsPico - CheckConnection - Internal Timer has been removed and restarted to check connection again in 300s";
  499. undef $ssh;
  500. return undef;
  501. }
  502. else
  503. {
  504. #### Try out with factory default address
  505. $cmd = "sudo i2cget -y 1 0x69 0x00 b";
  506. ($stdout, $stderr, $exit) = $ssh->cmd($cmd);
  507. if(defined($stderr)) { Log3 $name, 2, $name. " : UpsPico - CheckConnection - Obtain I2C range with 0x69 - stderr : " . $stderr;}
  508. if(defined($exit)) { Log3 $name, 5, $name. " : UpsPico - CheckConnection - Obtain I2C range with 0x69 - exit : " . $exit; }
  509. if(defined($stdout)) { Log3 $name, 5, $name. " : UpsPico - CheckConnection - Obtain I2C range with 0x69 - stdout : " . $stdout;}
  510. Log3 $name, 5, $name. " : UpsPico - CheckConnection ----------------------------------------------------------";
  511. ### If connection with status register on I2C address 0x69 was successfully
  512. if ($stdout ne "")
  513. {
  514. #### Try out whether RTC register are available
  515. $cmd = "sudo i2cget -y 1 0x6A 0x00 b";
  516. ($stdout, $stderr, $exit) = $ssh->cmd($cmd);
  517. if(defined($stderr)) { Log3 $name, 2, $name. " : UpsPico - CheckConnection - Obtain I2C range with 0x6A - stderr : " . $stderr;}
  518. if(defined($exit)) { Log3 $name, 5, $name. " : UpsPico - CheckConnection - Obtain I2C range with 0x6A - exit : " . $exit; }
  519. if(defined($stdout)) { Log3 $name, 5, $name. " : UpsPico - CheckConnection - Obtain I2C range with 0x6A - stdout : " . $stdout;}
  520. Log3 $name, 5, $name. " : UpsPico - CheckConnection ----------------------------------------------------------";
  521. ### If connection with RTC register on I2C address 0x6A was successfully
  522. if ($stdout ne "")
  523. {
  524. ### Set I2CRegisterRange to "NORMAL"
  525. $hash->{I2cRegisterRange} = "NORMAL";
  526. }
  527. else
  528. {
  529. ### Set I2CRegisterRange to "NO_RTC"
  530. $hash->{I2cRegisterRange} = "NO_RTC";
  531. }
  532. ###Initiate the timer for first time polling of values from UpsPico but wait 10s
  533. RemoveInternalTimer($hash);
  534. $hash->{temp}{FIRSTTIME} = true;
  535. InternalTimer(gettimeofday()+10, "UpsPico_GetAllData", $hash, 0);
  536. Log3 $name, 3, $name. " : UpsPico - CheckConnection - I2C range has been set to : " . $hash->{I2cRegisterRange};
  537. Log3 $name, 4, $name. " : UpsPico - CheckConnection - Internal timer for Initialisation of services started for the first time.";
  538. ###Set fullResponse error message
  539. readingsSingleUpdate( $hash, "fullResponse", "OK", 1);
  540. }
  541. ### If connection was not successfully
  542. else
  543. {
  544. #### Try out with alternate address
  545. $cmd = "sudo i2cget -y 1 0x59 0x00 b";
  546. ($stdout, $stderr, $exit) = $ssh->cmd($cmd);
  547. if(defined($stderr)) { Log3 $name, 2, $name. " : UpsPico - CheckConnection - Obtain I2C range with 0x5A - stderr : " . $stderr;}
  548. if(defined($exit)) { Log3 $name, 5, $name. " : UpsPico - CheckConnection - Obtain I2C range with 0x5A - exit : " . $exit; }
  549. if(defined($stdout)) { Log3 $name, 5, $name. " : UpsPico - CheckConnection - Obtain I2C range with 0x5A - stdout : " . $stdout;}
  550. Log3 $name, 5, $name. " : UpsPico - CheckConnection ----------------------------------------------------------";
  551. ### If connection with status register on I2C address 0x59 was successfully
  552. if ($stdout ne "")
  553. {
  554. $hash->{I2cRegisterRange} = "ALTERNATE";
  555. ###Initiate the timer for first time polling of values from UpsPico but wait 10s
  556. RemoveInternalTimer($hash);
  557. $hash->{temp}{FIRSTTIME} = true;
  558. InternalTimer(gettimeofday()+10, "UpsPico_GetAllData", $hash, 0);
  559. Log3 $name, 3, $name. " : UpsPico - CheckConnection - I2C range has been set to : " . $hash->{I2cRegisterRange};
  560. Log3 $name, 4, $name. " : UpsPico - CheckConnection - Internal timer for Initialisation of services started for the first time.";
  561. ###Set fullResponse error message
  562. readingsSingleUpdate( $hash, "fullResponse", "OK", 1);
  563. }
  564. ### Otherwise there is no UpsPIco connection available
  565. else
  566. {
  567. Log3 $name, 2, $name. " : UpsPico - CheckConnection - Connection to UPS-PIco could not be established. Terminating Initialisation!";
  568. ###Set fullResponse error message
  569. readingsSingleUpdate( $hash, "fullResponse", "Error I2C-connection failed. Check connection and re-define device.", 1);
  570. ### Stop the internal timer for this module and re-initiate the timer for another check of connection towards RasPi with UpsPico but wait 10s
  571. RemoveInternalTimer($hash);
  572. $hash->{temp}{FIRSTTIME} = true;
  573. InternalTimer(gettimeofday()+10, "UpsPico_CheckConnection", $hash, 0);
  574. Log3 $name, 4, $name. " : UpsPico - CheckConnection - Internal Timer has been removed and restarted to check connection again in 10s";
  575. return undef;
  576. }
  577. }
  578. }
  579. }
  580. Log3 $name, 5, $name. " : UpsPico ----------------------------------------------------------------------------------------------------------------";
  581. return undef;
  582. }
  583. ####END####### Check connection towards remote RasPi via SSH ###################################################END#####
  584. ###START###### Download all register ##########################################################################START####
  585. sub UpsPico_GetAllData($@)
  586. {
  587. my ($hash, $def) = @_;
  588. my $host = $hash->{URL};
  589. my $name = $hash->{NAME} ;
  590. my $user = $hash->{temp}{RemotePiUser};
  591. my $pass = $hash->{temp}{RemotePiPass};
  592. my $PollingInterval = $attr{$name}{PollingInterval};
  593. my %RegisterInfo = %{$hash->{temp}{RegisterInfo}};
  594. my %BattChargingInfo = %{$hash->{temp}{BattChargingInfo}};
  595. my $port = $attr{$name}{Port};
  596. my $ssh;
  597. my $ReturnMessage;
  598. ### Stop the current timer
  599. RemoveInternalTimer($hash);
  600. ###START###### Reset fullResponse error message ############################################################START####
  601. readingsSingleUpdate( $hash, "fullResponse", "Downloading...", 1);
  602. ####END####### Reset fullResponse error message #############################################################END#####
  603. ###START###### Set I2C address accordingly ###############################################################START####
  604. my %I2CAddress;
  605. if ($hash->{I2cRegisterRange} eq "NORMAL")
  606. {
  607. Log3 $name, 4, $name. " : UpsPico_GetAllData - I2CRegisterRange has been set to NORMAL";
  608. $I2CAddress{Status} = 0x69;
  609. $I2CAddress{RTC} = 0x6a;
  610. $I2CAddress{Command} = 0x6b;
  611. $I2CAddress{StartTS} = 0x6c;
  612. $I2CAddress{RunTS} = 0x6d;
  613. $I2CAddress{EventS} = 0x6e;
  614. $I2CAddress{ActionS} = 0x6f;
  615. }
  616. elsif ($hash->{I2cRegisterRange} eq "NO_RTC")
  617. {
  618. Log3 $name, 4, $name. " : UpsPico_GetAllData - I2CRegisterRange has been set to NO_RTC";
  619. $I2CAddress{Status} = 0x69;
  620. $I2CAddress{RTC} = undef;
  621. $I2CAddress{Command} = 0x6b;
  622. $I2CAddress{StartTS} = undef;
  623. $I2CAddress{RunTS} = undef;
  624. $I2CAddress{EventS} = undef;
  625. $I2CAddress{ActionS} = undef;
  626. }
  627. elsif ($hash->{I2cRegisterRange} eq "ALTERNATE")
  628. {
  629. Log3 $name, 4, $name. " : UpsPico_GetAllData - I2CRegisterRange has been set to ALTERNATE";
  630. $I2CAddress{Status} = 0x59;
  631. $I2CAddress{RTC} = 0x5a;
  632. $I2CAddress{Command} = 0x5b;
  633. $I2CAddress{StartTS} = 0x5c;
  634. $I2CAddress{RunTS} = 0x5d;
  635. $I2CAddress{EventS} = 0x5e;
  636. $I2CAddress{ActionS} = 0x5f;
  637. }
  638. ####END####### Set I2C address accordingly #################################################################END#####
  639. ###START###### Check whether all required attributes exists otherwise create them with standard values ###BEGIN####
  640. if(!defined($attr{$name}{Port}))
  641. {
  642. ### Set attribute with standard value since it is not available
  643. $attr{$name}{Port} = 22;
  644. ### Writing log entry
  645. Log3 $name, 3, $name. " : UpsPico - The attribute SSH-Port was missing and has been set to " . $attr{$name}{Port};
  646. }
  647. if(!defined($attr{$name}{PollingInterval}))
  648. {
  649. ### Set attribute with standard value since it is not available
  650. $attr{$name}{PollingInterval} = 300;
  651. ### Writing log entry
  652. Log3 $name, 3, $name. " : UpsPico - The attribute PollingInterval was missing and has been set to " . $attr{$name}{PollingInterval};
  653. }
  654. if(!defined($attr{$name}{room}))
  655. {
  656. ### Set attribute with standard value since it is not available
  657. $attr{$name}{room} = "UpsPIco";
  658. ### Writing log entry
  659. Log3 $name, 3, $name. " : UpsPico - The attribute for room was missing and has been set to " . $attr{$name}{room};
  660. }
  661. if(!defined($attr{$name}{WriteCritical}))
  662. {
  663. ### Set attribute with standard value since it is not available
  664. $attr{$name}{WriteCritical} = 0;
  665. ### Writing log entry
  666. Log3 $name, 3, $name. " : UpsPico - The attribute for allowing to write critical register was missing and has been set to " . $attr{$name}{WriteCritical};
  667. }
  668. if(!defined($attr{$name}{CredentialsEncrypted}))
  669. {
  670. ### Set attribute with standard value since it is not available
  671. $attr{$name}{CredentialsEncrypted} = 0;
  672. ### Writing log entry
  673. Log3 $name, 3, $name. " : UpsPico - The attribute for the Credentials being encrypted has been set to " . $attr{$name}{CredentialsEncrypted};
  674. }
  675. if(!defined($attr{$name}{DbLogExclude}))
  676. {
  677. ### Set attribute with standard value since it is not available
  678. $attr{$name}{DbLogExclude} = "/Status/pico_is_running";
  679. ### Writing log entry
  680. Log3 $name, 3, $name. " : UpsPico - The attribute for excluding the logging of the pico_is_running - status has been set.";
  681. }
  682. if(!defined($attr{$name}{"event-on-change-reading"}))
  683. {
  684. ### Set attribute with standard value since it is not available
  685. $attr{$name}{"event-on-change-reading"} = ".*";
  686. ### Writing log entry
  687. Log3 $name, 3, $name. " : UpsPico - The attribute for logging only on changed values has been set to all readings.";
  688. }
  689. ####END####### Check whether all required attributes exists otherwise create them with standard values ####END#####
  690. ###START###### Check connection ###########################################################################START####
  691. ### Check whether the network connection still exists
  692. eval {$ssh = Net::SSH::Perl->new($host);};
  693. if( $@ )
  694. {
  695. ###Set warning for log file
  696. Log3 $name, 1, $name. " : UpsPico_GetAllData - SSH Connection to RasPi with UPS-PIco could not be established. Terminating Initialisation!";
  697. ###Set fullResponse error message
  698. readingsSingleUpdate( $hash, "fullResponse", "Error: SSH-connection failed", 1);
  699. ### Stop the internal timer for this module and re-initiate the timer for another check of connection towards RasPi with UpsPico but wait 10s
  700. RemoveInternalTimer($hash);
  701. $hash->{temp}{FIRSTTIME} = true;
  702. InternalTimer(gettimeofday()+10, "UpsPico_CheckConnection", $hash, 0);
  703. Log3 $name, 4, $name. " : UpsPico_GetAllData - Error SSH-connection failed.";
  704. undef $ssh;
  705. return undef;
  706. }
  707. ### Check whether the credentials are still valid
  708. eval {$ssh->login($user, $pass);};
  709. if( $@ )
  710. {
  711. ###Set warning for log file
  712. Log3 $name, 1, $name. " : UpsPico_GetAllData - SSH Login to RasPi with UPS-PIco could not be established. Terminating Initialisation!";
  713. ###Set fullResponse error message
  714. readingsSingleUpdate( $hash, "fullResponse", "Error SSH-Login failed - Check Credentials", 1);
  715. ### Stop the internal timer for this module and re-initiate the timer for another check of connection towards RasPi with UpsPico but wait 10s
  716. RemoveInternalTimer($hash);
  717. $hash->{temp}{FIRSTTIME} = true;
  718. InternalTimer(gettimeofday()+10, "UpsPico_CheckConnection", $hash, 0);
  719. Log3 $name, 1, $name. " : UpsPico_GetAllData - Error SSH-Login failed - Check Credentials";
  720. undef $ssh;
  721. return undef;
  722. }
  723. ####END####### Check connection ############################################################################END#####
  724. ###START###### Download register block from UPS PIco via ssh command ######################################START####
  725. foreach my $RegisterI2CBlock (keys %I2CAddress)
  726. {
  727. ###START##### Download Register #######################################################################START####
  728. if (defined($I2CAddress{$RegisterI2CBlock}))
  729. {
  730. Log3 $name, 4, $name. " : UpsPico_GetAllData - working on Registerblock: " . $RegisterI2CBlock;
  731. my @RegisterBlock;
  732. my $stdout;
  733. my $stderr = 0;
  734. my $exit;
  735. my $SshCmd = "sudo i2cdump -y -r 0-255 1 " . int($I2CAddress{$RegisterI2CBlock}) . " b";
  736. ($stdout, $stderr, $exit) = $ssh->cmd($SshCmd);
  737. ### For debugging purposes only
  738. if(defined($stderr)) { Log3 $name, 2, $name. " : UpsPico_GetAllData - stderr " . $RegisterI2CBlock . " : " . $stderr; }
  739. if(defined($exit)) { Log3 $name, 5, $name. " : UpsPico_GetAllData - exit " . $RegisterI2CBlock . " : " . $exit; }
  740. if(defined($stdout)) { Log3 $name, 5, $name. " : UpsPico_GetAllData - stdout " . $RegisterI2CBlock . " : \n" . $stdout; }
  741. Log3 $name, 5, $name. " : UpsPico_GetAllData ------------------------------------------------------------------------------------";
  742. my @BlockRegister = split(/ /, $stdout);
  743. Log3 $name, 5, $name. " : UpsPico_GetAllData - BlockRegister" . $RegisterI2CBlock . " : \n" . Dumper \@BlockRegister;
  744. Log3 $name, 5, $name. " : UpsPico_GetAllData ------------------------------------------------------------------------------------";
  745. my $LineNumber;
  746. for ($LineNumber = 19; $LineNumber < 530; $LineNumber = $LineNumber + 2)
  747. {
  748. my @TempRegister = split(/ /, $BlockRegister[$LineNumber]);
  749. splice(@TempRegister, 0, 1);
  750. push(@RegisterBlock,@TempRegister);
  751. }
  752. Log3 $name, 4, $name. " : UpsPico_GetAllData - RegisterBlock " . $RegisterI2CBlock . " successfully downloaded";
  753. Log3 $name, 5, $name. " : UpsPico_GetAllData - RegisterBlock " . $RegisterI2CBlock . " : \n" . Dumper \@RegisterBlock;
  754. Log3 $name, 5, $name. " : UpsPico_GetAllData ------------------------------------------------------------------------------------";
  755. foreach my $RegisterName (keys %RegisterInfo)
  756. {
  757. ### If the Register-Information belongs to the current Register
  758. if ($RegisterInfo{$RegisterName}{RegisterBlockName} eq $RegisterI2CBlock)
  759. {
  760. if ($RegisterInfo{$RegisterName}{DataType} eq "Byte")
  761. {
  762. ### Mark SelectionList Item as not yet found
  763. my $FoundSelectionListItem = false;
  764. ### If SelectionList exists for this Register
  765. if ($RegisterInfo{$RegisterName}{SelectionList} ne undef)
  766. {
  767. ### Extract Selectionlist from hash
  768. my %SelectionList = %{$RegisterInfo{$RegisterName}{SelectionList}};
  769. ### For debugging purposes only
  770. Log3 $name, 5, $name. " : UpsPico_GetAllData -----------------Finding the Selection List entries for " . $RegisterName . "--------------------------------------------------------";
  771. Log3 $name, 5, $name. " : UpsPico_GetAllData - Register to be searched in SeletionListEntry : " . ($RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress}]);
  772. Log3 $name, 5, $name. " : UpsPico_GetAllData - Register to be searched in SeletionListEntry hex : " . hex($RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress}]);
  773. ### Search for the correct alias in the SelectionList
  774. foreach my $SeletionListEntry (keys %SelectionList)
  775. {
  776. Log3 $name, 5, $name. " : UpsPico_GetAllData - SeletionListEntry : " . ($SeletionListEntry);
  777. ### If the RegisterValue matches with the Key of the Selectionlist
  778. if ((($SeletionListEntry) eq hex($RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress}])) && ($SeletionListEntry ne "Default"))
  779. {
  780. Log3 $name, 5, $name. " : UpsPico_GetAllData - Found matching SeletionListEntry for : " . $SeletionListEntry . ". The value is: " . $SelectionList{$SeletionListEntry};
  781. ### Save the alias as value into the Register - hash
  782. $RegisterInfo{$RegisterName}{Value} = $SelectionList{$SeletionListEntry};
  783. Log3 $name, 4, $name. " : UpsPico_GetAllData - SelectionList Alias from " . $RegisterI2CBlock . " Register stored in Register-Hash for " . $RegisterName;
  784. ### Mark SelectionList Item as bein already found
  785. $FoundSelectionListItem = true;
  786. }
  787. ### If there is no match
  788. else
  789. {
  790. Log3 $name, 5, $name. " : UpsPico_GetAllData - Found NO matching SeletionListEntry for : " . $SeletionListEntry;
  791. ### Only set default value if the SelectionList item has not been found yet
  792. if ($FoundSelectionListItem == false)
  793. {
  794. ### Save the default value as value into the Register - hash
  795. $RegisterInfo{$RegisterName}{Value} = $SelectionList{Default};
  796. Log3 $name, 4, $name. " : UpsPico_GetAllData - SelectionList Default from " . $RegisterI2CBlock . " Register stored in Register-Hash for " . $RegisterName;
  797. }
  798. }
  799. }
  800. Log3 $name, 4, $name. " : UpsPico_GetAllData - Byte Value with SelectionList formation from " . $RegisterI2CBlock . " Register stored in Register-Hash for " . $RegisterName;
  801. ### If the SelectionList Vaulue is a mathematical function which needs to be calculated
  802. if (index($RegisterInfo{$RegisterName}{Value}, "Function: ") != -1)
  803. {
  804. ### Transform RegisterValue from hex into integer
  805. my $RegisterValue = hex($RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress}]);
  806. ### Extract formula from SelectionList
  807. my $MathExpression = $RegisterInfo{$RegisterName}{Value};
  808. ### Remove the keyword "Function " from the function string
  809. $MathExpression =~ s/Function: //;
  810. ### Create Parsing object for mathematical expression
  811. my $MathParsingObject = Math::Expression::Evaluator->new;
  812. ### Perform parsing and do calculation
  813. my $TempCalcResult = $MathParsingObject->parse("RegisterValue = " . $RegisterValue . "; " . $MathExpression)->val();
  814. ### Save the default value as value into the Register - hash
  815. $RegisterInfo{$RegisterName}{Value} = $TempCalcResult;
  816. ### For debugging purposes only
  817. Log3 $name, 5, $name. " : UpsPico_GetAllData - A mathematical formula has been found in the selection list.";
  818. Log3 $name, 5, $name. " : UpsPico_GetAllData - RegisterValue : " . $RegisterValue;
  819. Log3 $name, 5, $name. " : UpsPico_GetAllData - Expression of formula in SeletctionList : " . $MathExpression;
  820. Log3 $name, 5, $name. " : UpsPico_GetAllData - Result of formula in TempCalcResult : " . $TempCalcResult;
  821. }
  822. }
  823. ### If SelectionList does not exists for this Register
  824. else
  825. {
  826. ### If the Byte Value is bound to a unit and shown as hex corresponds to BCD
  827. if ($RegisterInfo{$RegisterName}{Unit} ne undef)
  828. {
  829. ### Just write Register-Value into Hash
  830. $RegisterInfo{$RegisterName}{Value} = $RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress}];
  831. Log3 $name, 4, $name. " : UpsPico_GetAllData - Byte Value as BCD from " . $RegisterI2CBlock . " Register stored in Register-Hash for " . $RegisterName;
  832. }
  833. ### If the Byte Value is not bound to a unit so do not transform it
  834. else
  835. {
  836. ### Just write Register-Value into Hash
  837. $RegisterInfo{$RegisterName}{Value} = "0x" . sprintf("%02d", $RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress}]);
  838. Log3 $name, 4, $name. " : UpsPico_GetAllData - Byte Value as hex from " . $RegisterI2CBlock . " Register stored in Register-Hash for " . $RegisterName;
  839. }
  840. }
  841. }
  842. elsif ($RegisterInfo{$RegisterName}{DataType} eq "WordBCD")
  843. {
  844. $RegisterInfo{$RegisterName}{Value} = int($RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress} + 1] . $RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress}]) * $RegisterInfo{$RegisterName}{Factor};
  845. Log3 $name, 4, $name. " : UpsPico_GetAllData - Word Value from " . $RegisterI2CBlock . " Register stored in Register-Hash for " . $RegisterName;
  846. Log3 $name, 5, $name. " : UpsPico_GetAllData - Word Value - RegisterBlock[RegisterInfo{RegisterName}{RegisterAddress} + 0 : " . $RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress} ] ;
  847. Log3 $name, 5, $name. " : UpsPico_GetAllData - Word Value - RegisterBlock[RegisterInfo{RegisterName}{RegisterAddress} + 1 : " . $RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress} + 1] ;
  848. Log3 $name, 5, $name. " : UpsPico_GetAllData - Word Value - RegisterBlock[RegisterInfo{RegisterName}{RegisterAddress} + 1 & +0 : " . $RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress} + 1] . $RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress}];
  849. Log3 $name, 5, $name. " : UpsPico_GetAllData - Word Value - RegisterInfo{RegisterName}{Factor} : " . $RegisterInfo{$RegisterName}{Factor};
  850. Log3 $name, 5, $name. " : UpsPico_GetAllData - Word Value - RegisterInfo{RegisterName}{Value} : " . $RegisterInfo{$RegisterName}{Value};
  851. }
  852. elsif ($RegisterInfo{$RegisterName}{DataType} eq "WordHex")
  853. {
  854. $RegisterInfo{$RegisterName}{Value} = hex($RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress} + 1] . $RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress}]) * $RegisterInfo{$RegisterName}{Factor};
  855. Log3 $name, 4, $name. " : UpsPico_GetAllData - Word Value from " . $RegisterI2CBlock . " Register stored in Register-Hash for " . $RegisterName;
  856. Log3 $name, 5, $name. " : UpsPico_GetAllData - Word Value - RegisterBlock[RegisterInfo{RegisterName}{RegisterAddress} + 0 : " . $RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress} ] ;
  857. Log3 $name, 5, $name. " : UpsPico_GetAllData - Word Value - RegisterBlock[RegisterInfo{RegisterName}{RegisterAddress} + 1 : " . $RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress} + 1] ;
  858. Log3 $name, 5, $name. " : UpsPico_GetAllData - Word Value - RegisterBlock[RegisterInfo{RegisterName}{RegisterAddress} + 1 & +0 : " . $RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress} + 1] . $RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress}];
  859. Log3 $name, 5, $name. " : UpsPico_GetAllData - Word Value - RegisterInfo{RegisterName}{Factor} : " . $RegisterInfo{$RegisterName}{Factor};
  860. Log3 $name, 5, $name. " : UpsPico_GetAllData - Word Value - RegisterInfo{RegisterName}{Value} : " . $RegisterInfo{$RegisterName}{Value};
  861. }
  862. elsif ($RegisterInfo{$RegisterName}{DataType} eq "ASCII")
  863. {
  864. $RegisterInfo{$RegisterName}{Value} = chr(hex($RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress}]));
  865. Log3 $name, 4, $name. " : UpsPico_GetAllData - ASCII Value from " . $RegisterI2CBlock . " Register stored in Register-Hash for " . $RegisterName;
  866. }
  867. elsif ($RegisterInfo{$RegisterName}{DataType} eq "Hex")
  868. {
  869. $RegisterInfo{$RegisterName}{Value} = hex($RegisterBlock[$RegisterInfo{$RegisterName}{RegisterAddress}]);
  870. Log3 $name, 4, $name. " : UpsPico_GetAllData - Hex Value from " . $RegisterI2CBlock . " Register transformed into Integer and stored in Register-Hash for " . $RegisterName;
  871. }
  872. else
  873. {
  874. $RegisterInfo{$RegisterName}{Value} = "ERROR";
  875. Log3 $name, 2, $name. " : UpsPico_GetAllData - ERROR - No Data Type found in Register-Hash for " . $RegisterName;
  876. }
  877. ### If the Register needs to be reset after reading, write 0x00 into register.
  878. if(($RegisterInfo{$RegisterName}{Reset} == true))
  879. {
  880. my $SshCmdStatus = "sudo i2cset -y 1 " . $I2CAddress{$RegisterI2CBlock} . " " . $RegisterInfo{$RegisterName}{RegisterAddress} . " 0";
  881. ($stdout, $stderr, $exit) = $ssh->cmd($SshCmdStatus);
  882. Log3 $name, 4, $name. " : UpsPico_GetAllData - Resetting Register to 0x00 for : " . $RegisterName;
  883. Log3 $name, 5, $name. " : UpsPico_GetAllData - SshCmdStatus : " . $SshCmdStatus;
  884. if(defined($stderr)) { Log3 $name, 2, $name. " : UpsPico_GetAllData - stderr Reset : " . $stderr; }
  885. if(defined($exit)) { Log3 $name, 5, $name. " : UpsPico_GetAllData - exit Reset : " . $exit; }
  886. if(defined($stdout)) { Log3 $name, 5, $name. " : UpsPico_GetAllData - stdout Reset : \n" . $stdout; }
  887. Log3 $name, 5, $name. " : UpsPico_GetAllData ------------------------------------------------------------------------------------";
  888. }
  889. ### Write current value
  890. readingsSingleUpdate($hash, "/" . $RegisterI2CBlock . "/" . $RegisterName, $RegisterInfo{$RegisterName}{Value},1);
  891. }
  892. }
  893. }
  894. ####END###### Download Register ########################################################################END#####
  895. }
  896. ####END####### Download register block from UPS PIco via ssh command #######################################END#####
  897. ###START###### Calculate and save Battery charging status #################################################START####
  898. Log3 $name, 5, $name. " : UpsPico_GetAllData - charge status - battype value : " . $RegisterInfo{"battype"}{Value};
  899. if ($RegisterInfo{"battype"}{Value} ne undef)
  900. {
  901. my $ChargeState;
  902. my $BattType = $RegisterInfo{"battype"}{Value};
  903. my $FoundBatteryItem = false;
  904. my $BattChargingState = "ERROR - No Battery found";
  905. ### Search for the correct alias in the SelectionList
  906. foreach my $BattInfoEntry (keys %BattChargingInfo)
  907. {
  908. Log3 $name, 5, $name. " : UpsPico_GetAllData - charge status - BattInfoEntry : " . $RegisterInfo{"battype"}{Value};
  909. ### If the entry has been found
  910. if ($BattInfoEntry eq $BattType)
  911. {
  912. ### For debugging purpose only
  913. Log3 $name, 5, $name. " : UpsPico_GetAllData - charge status - Found battype! ";
  914. Log3 $name, 5, $name. " : UpsPico_GetAllData - charge status - BattType : " . $BattInfoEntry;
  915. Log3 $name, 5, $name. " : UpsPico_GetAllData - charge status - 0 Percent Voltage : " . $BattChargingInfo{$BattInfoEntry}{Volt0Percent};
  916. Log3 $name, 5, $name. " : UpsPico_GetAllData - charge status - 100 Percent Voltage : " . $BattChargingInfo{$BattInfoEntry}{Volt100Percent};
  917. Log3 $name, 5, $name. " : UpsPico_GetAllData - charge status - Measured Voltage : " . $RegisterInfo{"batlevel"}{Value};
  918. my $BatVoltageLevel = $RegisterInfo{"batlevel"}{Value};
  919. ### Limit Voltagelevel to maximum to avoid indication of temporary overcharging
  920. if ($BatVoltageLevel > $BattChargingInfo{$BattInfoEntry}{Volt100Percent})
  921. {
  922. $BatVoltageLevel = $BattChargingInfo{$BattInfoEntry}{Volt100Percent}
  923. }
  924. ### Calculate Battery state of charging
  925. $BattChargingState = sprintf("%02d", ((($BatVoltageLevel - $BattChargingInfo{$BattInfoEntry}{Volt0Percent}) / ($BattChargingInfo{$BattInfoEntry}{Volt100Percent} - $BattChargingInfo{$BattInfoEntry}{Volt0Percent})) * 100));
  926. }
  927. }
  928. ### Write current value to reading and STATE
  929. readingsSingleUpdate($hash, "BattCharge", $BattChargingState,1);
  930. $hash->{STATE} = $BattChargingState;
  931. Log3 $name, 4, $name. " : UpsPico_GetAllData - charge status - BattChargingState : " . $BattChargingState;
  932. }
  933. ####END####### Calculate and save Battery charging status ##################################################END#####
  934. ### For Debugging purpose only
  935. Log3 $name, 5, $name. " : UpsPico_GetAllData - RegisterInfo in fhem-hash : \n" . Dumper \$hash->{temp}{RegisterInfo};
  936. Log3 $name, 5, $name. " : UpsPico_GetAllData -----------------------------------------------------------------";
  937. ### Close SSH session
  938. undef $ssh;
  939. Log3 $name, 4, $name. " : UpsPico_GetAllData - SSH session closed";
  940. Log3 $name, 5, $name. " : UpsPico_GetAllData ----------------------------------------------------------------------------------------------------------------";
  941. ####END####### Download register block from UPS PIco via ssh command #######################################END#####
  942. #### Initiate the timer for continuous polling of all data from UpsPico
  943. InternalTimer(gettimeofday()+$PollingInterval, "UpsPico_GetAllData", $hash, 0);
  944. Log3 $name, 4, $name. " : UpsPico_GetAllData - Define: InternalTimer for GettAllData re-started with interval of: " . $PollingInterval . " s";
  945. ###START###### Reset fullResponse error message ############################################################START####
  946. readingsSingleUpdate( $hash, "fullResponse", "Standby", 1);
  947. ####END####### Reset fullResponse error message #############################################################END#####
  948. }
  949. ####END####### Download all register ###########################################################################END#####
  950. 1;
  951. =pod
  952. =item device
  953. =item summary Connects fhem to UpsPIco on remote RasPi
  954. =item summary_DE Verbindet fhem mit einem UpsPIco auf einem entfernten RasPi
  955. =begin html
  956. <a name="UpsPico"></a>
  957. <h3>UpsPico</h3>
  958. <ul>
  959. <table>
  960. <tr>
  961. <td>
  962. The UpsPIco is an interruptible Power Supply for the Raspberry Pi from PiModules. This module is written for the Firmware Version 0x38 and above and has been tested on the "UPS PIco HV3.0A Stack Plus" only.<BR>
  963. This module provides all the internal data written in the UpsPIco register which are accessible via I2C - Bus. The set command is able to change the values in accordance to the specifications.<BR>
  964. For details to the Information contained in the register, please consult the internal register specification published in the latest manual. (See below)<BR>
  965. <BR>
  966. <u>References:</u><BR>
  967. <a href="http://www.pimodulescart.com/shop/item.aspx?itemid=29">UPS PIco HV3.0A Stack Plus</a><BR>
  968. <a href="http://www.forum.pimodules.com/viewforum.php?f=25">UPS PIco HV3.0A : Internal Register Specification, Manuals and Firmware Updates</a><BR>
  969. <BR>
  970. </td>
  971. </tr>
  972. </table>
  973. <table>
  974. <tr><td><a name="UpsPicodefine"></a><b>Define</b></td></tr>
  975. </table>
  976. <table><tr><td><ul><code>define &lt;name&gt; UpsPico &lt;IPv4-address&gt; &lt;Username&gt; &lt;Password&gt;</code></ul></td></tr></table>
  977. <ul><ul>
  978. <table>
  979. <tr><td><code>&lt;name&gt;</code> : </td><td>The name of the device. Recommendation: "myUpsPico".</td></tr>
  980. <tr><td><code>&lt;IPv4-address&gt;</code> : </td><td>A valid IPv4 address of the Raspberry Pi with UpsPIco. You might look into your router which DHCP address has been given to the RasPi.</td></tr>
  981. <tr><td><code>&lt;GatewayPassword&gt;</code> : </td><td>The username of the remote Raspberry Pi.</td></tr>
  982. <tr><td><code>&lt;PrivatePassword&gt;</code> : </td><td>The password of the remote Raspberry Pi.</td></tr>
  983. </table>
  984. </ul></ul>
  985. <BR>
  986. <table>
  987. <tr><td><a name="UpsPicoSet"></a><b>Set</b></td></tr>
  988. <tr><td>
  989. <ul>
  990. The set function is able to change a value which is marked as writeable.<BR>
  991. If the register is considered as a critical setting (e.g. a wrong value might result in permanent damage), the attribute "WriteCritical" must be set to "1" = yes beforehand.
  992. </ul>
  993. </td></tr>
  994. </table>
  995. <table><tr><td><ul><code>set &lt;name&gt; &lt;register&gt; &lt;value&gt;</code></ul></td></tr></table>
  996. <ul><ul>
  997. <table>
  998. <tr><td><code>&lt;name&gt;</code> : </td><td>The name of the defined UpsPico device<BR></td></tr>
  999. <tr><td><code>&lt;register&gt;</code> : </td><td>The name of the register which value shall be set. E.g.: "<code>/Status/key</code>"<BR></td></tr>
  1000. <tr><td><code>&lt;value&gt;</code> : </td><td>A valid value for this register.<BR></td></tr>
  1001. </table>
  1002. </ul></ul>
  1003. <BR>
  1004. <table>
  1005. <tr><td><a name="UpsPicoGet"></a><b>Get</b></td></tr>
  1006. <tr><td>
  1007. <ul>
  1008. The get function is able to obtain a value of a register.<BR>
  1009. It returns only the value but not the unit or the range or list of allowed values possible.<BR>
  1010. </ul>
  1011. </td></tr>
  1012. </table>
  1013. <table><tr><td><ul><code>get &lt;name&gt; &lt;register&gt;</code></ul></td></tr></table>
  1014. <ul><ul>
  1015. <table>
  1016. <tr><td><code>&lt;name&gt;</code> : </td><td>The name of the defined UpsPico device<BR></td></tr>
  1017. <tr><td><code>&lt;register&gt;</code> : </td><td>The name of the register which value shall be obtained. E.g.: "<code>/Status/key</code>"<BR></td></tr>
  1018. </td>
  1019. </tr>
  1020. </table>
  1021. </ul></ul>
  1022. <BR>
  1023. <table>
  1024. <tr><td><a name="UpsPicoAttr"></a><b>Attributes</b></td></tr>
  1025. <tr><td>
  1026. <ul>
  1027. <BR>
  1028. The following user attributes can be used with the UpsPico module in addition to the general ones e.g. <a href="#room">room</a>.<BR>
  1029. </ul>
  1030. </td></tr>
  1031. </table>
  1032. <table>
  1033. <td>
  1034. <ul><ul>
  1035. <tr>
  1036. <td>
  1037. <BR>
  1038. <tr><td><ul><li><code>PollingInterval</code> : </li></td><td>A valid polling interval for the values of the UPS PIco. The value must be >=20s to allow the UpsPico module to perform a full polling procedure. <BR>
  1039. The default value is 300s.<BR>
  1040. </ul></td></tr>
  1041. </td>
  1042. </tr>
  1043. </ul></ul>
  1044. <ul><ul>
  1045. <tr>
  1046. <td>
  1047. <BR>
  1048. <tr><td><ul><li><code>WriteCritical</code> : </li></td><td>Prevents acidential damaging of the UpsPico hardware by change of critical register with wrong values.<BR>
  1049. The attribute must be re-activated for every single set-command.<BR>
  1050. The default value is 0 = deactivated<BR>
  1051. </ul></td></tr>
  1052. </td>
  1053. </tr>
  1054. </ul></ul>
  1055. <ul><ul>
  1056. <tr>
  1057. <td>
  1058. <BR>
  1059. <tr><td><ul><li><code>Port</code> : </li></td><td>The port number for the SSH access on the remote system.<BR>
  1060. The default value is 22 = Standard SSH port<BR>
  1061. </ul></td></tr>
  1062. </td>
  1063. </tr>
  1064. </ul></ul>
  1065. <ul><ul>
  1066. <tr>
  1067. <td>
  1068. <BR>
  1069. <tr><td><ul><li><code>CredentialsEncrypted</code> : </li></td><td>This attributes will swap from plain text to base64 encrypted credentials in the definition.<BR>
  1070. The default value is 0 = Plain Text Credentials<BR>
  1071. </ul></td></tr>
  1072. </td>
  1073. </tr>
  1074. </ul></ul>
  1075. <ul><ul>
  1076. <tr>
  1077. <td>
  1078. <BR>
  1079. <tr><td><ul><li><code>DbLogExclude</code> : </li></td><td>This general attribute will be set automatically to the reading "/Status/pico_is_running" which is a continously counting WatchDog register.<BR>
  1080. It makes no sense to log this reading.<BR>
  1081. The default exclusion from logging is "/Status/pico_is_running" <BR>
  1082. </ul></td></tr>
  1083. </td>
  1084. </tr>
  1085. </ul></ul>
  1086. <ul><ul>
  1087. <tr>
  1088. <td>
  1089. <BR>
  1090. <tr><td><ul><li><code>event-on-change-reading</code> : </li></td><td>This general attribute will be set automatically to ".*" which prevents unchanged but updated readings to be logged.<BR>
  1091. The default value is ".*" = Apply to all readings.<BR>
  1092. </ul></td></tr>
  1093. </td>
  1094. </tr>
  1095. </ul></ul>
  1096. <ul><ul>
  1097. <tr>
  1098. <td>
  1099. <BR>
  1100. <tr><td><ul><li><code>room</code> : </li></td><td>This general attribute will be set automatically to "UpsPIco" which prevents the device getting lost in the "Everything" room.<BR>
  1101. The default value is "UpsPIco".<BR>
  1102. </ul></td></tr>
  1103. </td>
  1104. </tr>
  1105. </ul></ul>
  1106. </td>
  1107. </table>
  1108. </ul>
  1109. =end html
  1110. =begin html_DE
  1111. <a name="UpsPico"></a>
  1112. <h3>UpsPico</h3>
  1113. <ul>
  1114. <table>
  1115. <tr>
  1116. <td>
  1117. Der UpsPIco ist eine unterbrechungsfreie Stroimversorgung f&uuml;r den Raspberry Pi von PiModules. Dieses Modul wurde f&uuml;r die Firmware ab Version 0x38 und h&ouml;her geschrieben und wurde nur auf dem "UPS PIco HV3.0A Stack Plus" getestet.<BR>
  1118. Dieses Modul stellt alle internen Daten zur Verf&uuml;gung, welche in die UpsPIco Register geschrieben und &uuml;ber den I2C - Bus ausgelesen werden. Der set-Befehl ist dar&uuml;ber hinaus in der Lage die Werte der Register entsprechend Ihrer Spezifikation zu &auml;ndern.<BR>
  1119. Detailierte Informationen zu den einzelnen Registern stehen in den Register Spezifikationen in der letzten ver&ouml;ffentlichten Anleitung. (Siehe unten)<BR>
  1120. <BR>
  1121. <u>Referenzen:</u><BR>
  1122. <a href="http://www.pimodulescart.com/shop/item.aspx?itemid=29">UPS PIco HV3.0A Stack Plus</a><BR>
  1123. <a href="http://www.forum.pimodules.com/viewforum.php?f=25">UPS PIco HV3.0A : Interne Register Spezification, Anleitung and Firmware Updates</a><BR>
  1124. <BR>
  1125. </td>
  1126. </tr>
  1127. </table>
  1128. <table>
  1129. <tr><td><a name="UpsPicodefine"></a><b>Define</b></td></tr>
  1130. </table>
  1131. <table><tr><td><ul><code>define &lt;name&gt; UpsPico &lt;IPv4-address&gt; &lt;Username&gt; &lt;Password&gt;</code></ul></td></tr></table>
  1132. <ul><ul>
  1133. <table>
  1134. <tr><td><code>&lt;name&gt;</code> : </td><td>Der Name des Device. Empfehlung: "myUpsPico".</td></tr>
  1135. <tr><td><code>&lt;IPv4-address&gt;</code> : </td><td>Eine g&uuml;ltige IPv4 Adresse des Raspberry Pi mit UpsPIco. Gegebenenfalls muss der Router f&uuml;r die an den Raspberry Pi vergebene DHCP Adresse konsultiert werden.</td></tr>
  1136. <tr><td><code>&lt;GatewayPassword&gt;</code> : </td><td>Der Username des entfernten Raspberry Pi.</td></tr>
  1137. <tr><td><code>&lt;PrivatePassword&gt;</code> : </td><td>Das Passwort des entfernten Raspberry Pi.</td></tr>
  1138. </table>
  1139. </ul></ul>
  1140. <BR>
  1141. <table>
  1142. <tr><td><a name="UpsPicoSet"></a><b>Set</b></td></tr>
  1143. <tr><td>
  1144. <ul>
  1145. Diese Funktion ver&auml;ndert die Werte der register, welche als beschreibbar definiert sind.<BR>
  1146. Sind die entsprechenden Register als kritisch (critical) spezifiziert (Ein falscher Wert k&ouml;nnte zur Besch&auml;digung des UpsPIco f&uuml;hren), muss das Atttribut "WriteCritical" vorher auf "1" gesetzt werden.
  1147. </ul>
  1148. </td></tr>
  1149. </table>
  1150. <table><tr><td><ul><code>set &lt;name&gt; &lt;register&gt; &lt;value&gt;</code></ul></td></tr></table>
  1151. <ul><ul>
  1152. <table>
  1153. <tr><td><code>&lt;name&gt;</code> : </td><td>Der name des definierten UpsPico Device<BR></td></tr>
  1154. <tr><td><code>&lt;register&gt;</code> : </td><td>Der name des Registers welches ver&auml;ndert werden soll. E.g.: "<code>/Status/key</code>"<BR></td></tr>
  1155. <tr><td><code>&lt;value&gt;</code> : </td><td>Ein g&uuml;ltiger Wert f&uuml;r das Register.<BR></td></tr>
  1156. </table>
  1157. </ul></ul>
  1158. <BR>
  1159. <table>
  1160. <tr><td><a name="UpsPicoGet"></a><b>Get</b></td></tr>
  1161. <tr><td>
  1162. <ul>
  1163. Die get Funktion liest einzelne Register aus und schreibt sie in das entsprechende Reading.<BR>
  1164. Es wird nur der Wert, aber nicht die Einheit oder der g&uuml;ltige Wertebereich zur&uuml;ckgegeben.<BR>
  1165. </ul>
  1166. </td></tr>
  1167. </table>
  1168. <table><tr><td><ul><code>get &lt;name&gt; &lt;register&gt;</code></ul></td></tr></table>
  1169. <ul><ul>
  1170. <table>
  1171. <tr><td><code>&lt;name&gt;</code> : </td><td>Der name des definierten UpsPico Device<BR></td></tr>
  1172. <tr><td><code>&lt;register&gt;</code> : </td><td>Der name des Registers welches ausgelesen werden soll. E.g.: "<code>/Status/key</code>"<BR></td></tr>
  1173. </td>
  1174. </tr>
  1175. </table>
  1176. </ul></ul>
  1177. <BR>
  1178. <table>
  1179. <tr><td><a name="UpsPicoAttr"></a><b>Attributes</b></td></tr>
  1180. <tr><td>
  1181. <ul>
  1182. <BR>
  1183. Die folgenden Attribute k&ouml;nnen neben den allgemeinen Attributen wie <a href="#room">room</a> vergeben werden.<BR>
  1184. </ul>
  1185. </td></tr>
  1186. </table>
  1187. <table>
  1188. <td>
  1189. <ul><ul>
  1190. <tr>
  1191. <td>
  1192. <BR>
  1193. <tr><td><ul><li><code>PollingInterval</code> : </li></td><td>Abrageinterval f&uuml;r den UPS PIco. Der Wert muss >=20s sein um einen vollen Polling Zyklus zu erlauben.<BR>
  1194. Der Defaul Wert ist 300s.<BR>
  1195. </ul></td></tr>
  1196. </td>
  1197. </tr>
  1198. </ul></ul>
  1199. <ul><ul>
  1200. <tr>
  1201. <td>
  1202. <BR>
  1203. <tr><td><ul><li><code>WriteCritical</code> : </li></td><td>Verhindert versehentliche Besch&auml;digungen durch Beschreiben der kritischen Register mit falschen Werten.<BR>
  1204. Musz f&uuml;r jeden einzelnen Schreibvorgang erneut gesetzt werden da dieser zur&uuml;ckgesetzt wird..<BR>
  1205. Der Default Wert ist 0 = Deaktiviert.<BR>
  1206. </ul></td></tr>
  1207. </td>
  1208. </tr>
  1209. </ul></ul>
  1210. <ul><ul>
  1211. <tr>
  1212. <td>
  1213. <BR>
  1214. <tr><td><ul><li><code>Port</code> : </li></td><td>Port Nummer f&uuml;r den SSH Zugang am entfernten Raspberry Pi.<BR>
  1215. Der Default Wert ist 22 = Standard SSH Port<BR>
  1216. </ul></td></tr>
  1217. </td>
  1218. </tr>
  1219. </ul></ul>
  1220. <ul><ul>
  1221. <tr>
  1222. <td>
  1223. <BR>
  1224. <tr><td><ul><li><code>CredentialsEncrypted</code> : </li></td><td>Definiert ob die Anmeldedaten in lesbarer Form (PlainText) oder als base64 verschl&uuml;sselt vorliegen.<BR>
  1225. Der Default Wert ist 0 = Anmeldedaten liegen in PlainText vor.<BR>
  1226. </ul></td></tr>
  1227. </td>
  1228. </tr>
  1229. </ul></ul>
  1230. <ul><ul>
  1231. <tr>
  1232. <td>
  1233. <BR>
  1234. <tr><td><ul><li><code>DbLogExclude</code> : </li></td><td>Generelles Attribut um Readings von Loggen auszuschließen. Das Attribut wird automatisch auf "/Status/pico_is_running" gesetzt welchen den kontinuierlichen Watchdog Z&auml;hler vom loggen ausnimmt.<BR>
  1235. Es ergibt keinen Sinn dieses Reading zu loggen.<BR>
  1236. Der Default Wert f&uuml;r die Ausnahme vom loggen liegt auf dem Reading "/Status/pico_is_running" <BR>
  1237. </ul></td></tr>
  1238. </td>
  1239. </tr>
  1240. </ul></ul>
  1241. <ul><ul>
  1242. <tr>
  1243. <td>
  1244. <BR>
  1245. <tr><td><ul><li><code>event-on-change-reading</code> : </li></td><td>Generelles Attribut um Events nur bei &auml;nderungen von Readings zu erzeugen. Das Attribut wird automatisch auf ".*" gesetzt, was alle Readings nur bei &auml;nderungen loggt.<BR>
  1246. Der Default Wert ist ".*" = Alle Readings.<BR>
  1247. </ul></td></tr>
  1248. </td>
  1249. </tr>
  1250. </ul></ul>
  1251. <ul><ul>
  1252. <tr>
  1253. <td>
  1254. <BR>
  1255. <tr><td><ul><li><code>room</code> : </li></td><td>Generelles Attribut zum setzen des Raumes. Das Attribut wird automatisch auf "UpsPIco" gesetzt, damit das device nicht im "Everthing" Raum verschwindet.<BR>
  1256. Der Default Wert ist "UpsPIco".<BR>
  1257. </ul></td></tr>
  1258. </td>
  1259. </tr>
  1260. </ul></ul>
  1261. </td>
  1262. </table>
  1263. </ul>
  1264. =end html_DE