89_VCONTROL.pm 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825
  1. #################################################################################
  2. #
  3. # $Id: 89_VCONTROL.pm 11776 2016-07-10 13:57:22Z adamwit $
  4. #
  5. # FHEM Module for Viessman Vitotronic200 / Typ KW1 und KW2
  6. #
  7. # Derived from 89_VCONTROL.pm: Copyright (C) Adam WItalla
  8. #
  9. #
  10. # This program is free software; you can redistribute it and/or
  11. # modify it under the terms of the GNU General Public License
  12. # as published by the Free Software Foundation; either version 2
  13. # of the License, or (at your option) any later version.
  14. #
  15. # This program is distributed in the hope that it will be useful,
  16. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. # GNU General Public License for more details.
  19. #
  20. # You should have received a copy of the GNU General Public License
  21. # along with this program; if not, write to the Free Software
  22. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  23. #
  24. # The GNU General Public License may also be found at http://www.gnu.org/licenses/gpl-2.0.html .
  25. #
  26. ###########################
  27. #package main;
  28. use strict;
  29. use warnings;
  30. use Time::HiRes qw(gettimeofday);
  31. use Time::Local;
  32. # Helper Constants
  33. use constant NO_SEND => 9999;
  34. use constant POLL_ACTIVE => 1;
  35. use constant POLL_PAUSED => 0;
  36. use constant READ_ANSWER => 1;
  37. use constant READ_UNDEF => 0;
  38. use constant GET_TIMER_ACTIVE => 1;
  39. use constant GET_TIMER_PAUSED => 0;
  40. use constant GET_CONFIG_ACTIVE => 1;
  41. use constant GET_CONFIG_PAUSED => 0;
  42. use constant PROTOCOL_KW => 1;
  43. use constant PROTOCOL_GWG => 2;
  44. use constant PROTOCOL_300 => 3;
  45. my $viess_protocol = PROTOCOL_KW;
  46. #Poll Parameter
  47. my $defaultPollInterval = 180;
  48. my $last_cmd = 0;
  49. my $poll_now = POLL_PAUSED;
  50. my $get_timer_now = GET_TIMER_PAUSED;
  51. my $get_config_now = GET_CONFIG_PAUSED;
  52. my $command_config_file = "";
  53. my $poll_duration = 0;
  54. #Send Parameter
  55. my $send_now = NO_SEND;
  56. my $send_additonal_param="";
  57. #Get Parameter
  58. #Answer Parameter
  59. my $read_now = READ_UNDEF;
  60. #actually used command list
  61. my @cmd_list;
  62. my @poll_cmd_list;
  63. my @write_cmd_list;
  64. my @timer_cmd_list;
  65. my @set_cmd_list;
  66. my @get_timer_cmd_list;
  67. #remember days for daystart values
  68. my %DayHash;
  69. #States the Heater can be set to
  70. my @mode = ("WW","RED","NORM","H+WW","H+WW FS","ABSCHALT");
  71. my $temp_mode=0;
  72. #define TCP Connection (1) or USB device (0)
  73. my $TCP_CONNECTION = 0;
  74. ######################################################################################
  75. sub VCONTROL_1ByteUParse($$);
  76. sub VCONTROL_1ByteU2Parse($$);
  77. sub VCONTROL_1ByteSParse($$);
  78. sub VCONTROL_2ByteSParse($$);
  79. sub VCONTROL_2ByteUParse($$);
  80. sub VCONTROL_1ByteHexParse($);
  81. sub VCONTROL_2ByteHexParse($);
  82. sub VCONTROL_2BytePercentParse($$);
  83. sub VCONTROL_4ByteParse($$);
  84. sub VCONTROL_timerParse($);
  85. sub VCONTROL_ModusParse($);
  86. sub VCONTROL_DateParse($);
  87. sub VCONTROL_1ByteUConv($$);
  88. sub VCONTROL_1ByteSConv($$);
  89. sub VCONTROL_1ByteUx10Conv($);
  90. sub VCONTROL_2ByteUConv($$);
  91. sub VCONTROL_2ByteSConv($$);
  92. sub VCONTROL_DateConv($);
  93. sub VCONTROL_TimerConv($$);
  94. sub VCONTROL_RegisterConv($);
  95. sub VCONTROL_Clear($);
  96. sub VCONTROL_Read($);
  97. sub VCONTROL_Ready($);
  98. sub VCONTROL_Parse($$$$);
  99. sub VCONTROL_Poll($);
  100. sub VCONTROL_CmdConfig($);
  101. sub VCONTROL_ReInit($);
  102. sub VCONTROL_Initialize($)
  103. {
  104. my ($hash) = @_;
  105. require "$attr{global}{modpath}/FHEM/DevIo.pm";
  106. $hash->{ReadFn} = "VCONTROL_Read";
  107. #$hash->{WriteFn} = "VCONTROL_Write";
  108. $hash->{ReadyFn} = "VCONTROL_Ready";
  109. $hash->{DefFn} = "VCONTROL_Define";
  110. $hash->{UndefFn} = "VCONTROL_Undef";
  111. $hash->{SetFn} = "VCONTROL_Set";
  112. $hash->{GetFn} = "VCONTROL_Get";
  113. $hash->{StateFn} = "VCONTROL_SetState";
  114. $hash->{ShutdownFn} = "VCONTROL_Shutdown";
  115. $hash->{AttrList} = "disable:0,1 init_every_poll:0,1 update_only_changes:0,1 setList closedev:0,1 ". $readingFnAttributes;
  116. }
  117. #####################################
  118. # define <name> VIESSMANN <port> <command_config> [<interval>]
  119. sub VCONTROL_Define($$)
  120. {
  121. my ($hash, $def) = @_;
  122. my @a = split("[ \t][ \t]*", $def);
  123. my $po;
  124. if (@a != 4 && @a != 5) {
  125. my $msg = "wrong syntax: define <name> VCONTROL <port> <command_config> [<interval>]";
  126. Log3 undef, 2, $msg;
  127. return $msg;
  128. }
  129. #Determine if USB device or TCP Connection is used
  130. if (index($a[2], ':') == -1) {
  131. ###USB
  132. delete $hash->{USBDev};
  133. delete $hash->{FD};
  134. }
  135. else {
  136. ###TCP Connection
  137. $TCP_CONNECTION = 1;
  138. }
  139. #Close Device to initialize properly
  140. DevIo_CloseDev($hash);
  141. my $name = $a[0];
  142. my $dev = $a[2];
  143. #check existence of config_file
  144. if($a[3]){
  145. $command_config_file = $a[3];
  146. if(-e $command_config_file){
  147. Log3 $name, 3, "VCONTROL: Define open DATEI '$command_config_file'";
  148. VCONTROL_CmdConfig($command_config_file);
  149. }
  150. else {
  151. my $msg = "config file $command_config_file does not exist";
  152. Log3 undef, 2, $msg;
  153. return $msg;
  154. }
  155. }
  156. #set command list to poll list
  157. @cmd_list = @poll_cmd_list;
  158. #use configured Pollinterval if given
  159. if($a[4]){
  160. $hash->{INTERVAL} = $a[4];
  161. }
  162. else {
  163. $hash->{INTERVAL} = $defaultPollInterval;
  164. }
  165. $hash->{STATE} = "defined";
  166. $hash->{DeviceName} = $dev;
  167. $hash->{PARTIAL} = "";
  168. #Opening USB Device
  169. Log3($name, 3, "VCONTROL opening VCONTROL device $dev");
  170. my $ret = undef;
  171. if ($TCP_CONNECTION == 0) {
  172. ###USB
  173. if ($^O=~/Win/) {
  174. require Win32::SerialPort;
  175. $po = new Win32::SerialPort ($dev);
  176. } else {
  177. require Device::SerialPort;
  178. $po = new Device::SerialPort ($dev);
  179. }
  180. if(!$po) {
  181. my $msg = "Can't open $dev: $!";
  182. Log3($name, 3, $msg) if($hash->{MOBILE});
  183. return $msg if(!$hash->{MOBILE});
  184. $readyfnlist{"$name.$dev"} = $hash;
  185. return "";
  186. }
  187. Log3($name, 3, "VCONTROL opened VCONTROL device $dev");
  188. $hash->{USBDev} = $po;
  189. if( $^O =~ /Win/ ) {
  190. $readyfnlist{"$name.$dev"} = $hash;
  191. } else {
  192. $hash->{FD} = $po->FILENO;
  193. delete($readyfnlist{"$name.$dev"});
  194. $selectlist{"$name.$dev"} = $hash;
  195. }
  196. #Initialize to be able to receive data
  197. VCONTROL_DoInit($hash, $po);
  198. }
  199. else {
  200. ###TCP Connection
  201. $ret = DevIo_OpenDev($hash, 0, "VCONTROL_DoInit");
  202. }
  203. #set Internal Timer on Polling Interval
  204. my $timer = gettimeofday()+1;
  205. Log3($name, 5, "VCONTROL set InternalTimer +1 to $timer");
  206. RemoveInternalTimer($hash);
  207. InternalTimer(gettimeofday()+1, "VCONTROL_Poll", $hash, 0);
  208. return $ret;
  209. }
  210. #####################################
  211. # Input is hexstring
  212. ## This function will not be used until now!
  213. #sub VCONTROL_Write($$)
  214. #{
  215. # my ($hash,$fn,$msg) = @_;
  216. # my $name = $hash->{NAME};
  217. #
  218. # return if(!defined($fn));
  219. #
  220. # my $bstring;
  221. # $bstring = "$fn$msg";
  222. # Log3 $name, 5, "$hash->{NAME} sending $bstring";
  223. #
  224. # DevIo_SimpleWrite($hash, $bstring, 1);
  225. #}
  226. #####################################
  227. sub VCONTROL_Undef($$)
  228. {
  229. my ($hash, $arg) = @_;
  230. my $name = $hash->{NAME};
  231. foreach my $d (sort keys %defs) {
  232. if(defined($defs{$d}) &&
  233. defined($defs{$d}{IODev}) &&
  234. $defs{$d}{IODev} == $hash)
  235. {
  236. my $lev = ($reread_active ? 4 : 2);
  237. Log3 $name, $lev, "deleting port for $d";
  238. delete $defs{$d}{IODev};
  239. }
  240. }
  241. RemoveInternalTimer($hash);
  242. DevIo_CloseDev($hash);
  243. return undef;
  244. }
  245. #####################################
  246. sub VCONTROL_Poll($)
  247. {
  248. my $hash = shift;
  249. my $name = $hash->{NAME};
  250. #global Module Trigger that Polling is started
  251. if( AttrVal($name, "disable", 0 ) == 1 )
  252. {
  253. $poll_now = POLL_PAUSED;
  254. Log3 $name, 5, "VCONTROL: Poll disabled!";
  255. }
  256. else
  257. { $poll_now = POLL_ACTIVE;
  258. if( AttrVal($name, "init_every_poll", 0 ) == 1 )
  259. {
  260. VCONTROL_ReInit($hash);
  261. }
  262. }
  263. $poll_duration = gettimeofday();
  264. Log3 $name, 4, "VCONTROL: Start of Poll !";
  265. my $timer = gettimeofday()+$hash->{INTERVAL};
  266. Log3($name, 5, "VCONTROL: set InternalTimer to $timer");
  267. InternalTimer(gettimeofday()+$hash->{INTERVAL}, "VCONTROL_Poll", $hash, 0);
  268. }
  269. #####################################
  270. sub VCONTROL_Shutdown($)
  271. {
  272. my ($hash) = @_;
  273. return undef;
  274. }
  275. #####################################
  276. sub VCONTROL_SetState($$$$)
  277. {
  278. my ($hash, $tim, $vt, $val) = @_;
  279. return undef;
  280. }
  281. #####################################
  282. sub VCONTROL_Clear($)
  283. {
  284. my $hash = shift;
  285. my $buf;
  286. # clear buffer:
  287. if($hash->{USBDev}) {
  288. while ($hash->{USBDev}->lookfor()) {
  289. $buf = DevIo_SimpleRead($hash);
  290. }
  291. }
  292. if($hash->{TCPDev}) {
  293. # TODO
  294. return $buf;
  295. }
  296. }
  297. #####################################
  298. sub VCONTROL_DoInit($$)
  299. {
  300. #Initialisation -> Send one 0x04 so the heating started to send 0x05 Synchronity-Bytes
  301. my ($hash,$po) = @_;
  302. my $name = $hash->{NAME};
  303. my $init = pack('H*', "04");
  304. if ($po)
  305. {
  306. #set USB Device Parameter
  307. $po->reset_error();
  308. $po->baudrate(4800);
  309. $po->databits(8);
  310. $po->parity('even');
  311. $po->stopbits(2);
  312. $po->handshake('none');
  313. $po->write_settings;
  314. }
  315. $defs{$name}{STATE} = "Initialized";
  316. DevIo_SimpleWrite($hash, $init, 0);
  317. Log3 $name, 3,"VCONTROL: Initialization";
  318. return undef;
  319. }
  320. #####################################
  321. # called from the global loop, when the select for hash->{FD} reports data
  322. sub VCONTROL_Read($)
  323. {
  324. my ($hash) = @_;
  325. my $name = $hash->{NAME};
  326. Log3 $name, 5,"VCONTROL_READ";
  327. # count the commands to send for complete poll sequence
  328. my $cmdcount = @cmd_list;
  329. #Read on Device
  330. my $mybuf = DevIo_SimpleRead($hash);
  331. if(!defined($mybuf) || length($mybuf) == 0) {
  332. #Lost connection to the device
  333. if ($TCP_CONNECTION == 0) {
  334. #USB device
  335. my $dev = $hash->{DeviceName};
  336. Log3 $name, 3,"VCONTROL: USB device $dev disconnected, waiting to reappear";
  337. #$hash->{USBDev}->close();
  338. DoTrigger($name, "DISCONNECTED");
  339. DevIo_Disconnected($hash);
  340. delete($hash->{USBDev});
  341. delete($selectlist{"$name.$dev"});
  342. $readyfnlist{"$name.$dev"} = $hash; # Start polling
  343. $hash->{STATE} = "disconnected";
  344. # Without the following sleep the open of the device causes a SIGSEGV,
  345. # and following opens block infinitely. Only a reboot helps.
  346. sleep(5);
  347. return "";
  348. }
  349. else {
  350. #TCP Connection
  351. my $dev = $hash->{DeviceName};
  352. Log3 $name, 3,"VCONTROL: LAN device $dev disconnected, waiting to reappear";
  353. DevIo_Disconnected($hash);
  354. $hash->{STATE} = "disconnected";
  355. return "";
  356. }
  357. }
  358. #msg read on device
  359. my $hexline = unpack('H*', $mybuf);
  360. Log3 $name, 5,"VCONTROL: VCONTROL_Read '$hexline'";
  361. #Append data to partial data we got before
  362. #ADW: 05 muss auch angehängt werden!
  363. if ( $read_now == READ_ANSWER && $poll_now == POLL_ACTIVE ){
  364. # if ( $read_now == READ_ANSWER && $poll_now == POLL_ACTIVE && $hexline ne "05"){
  365. $hexline = $hash->{PARTIAL}.$hexline;
  366. #if not received all bytes exit an read next
  367. my $receive_len = 0;
  368. if ($viess_protocol == PROTOCOL_KW ) {
  369. $receive_len = hex(substr($cmd_list[$last_cmd][1],8,2))*2;
  370. } elsif ($viess_protocol == PROTOCOL_GWG ) {
  371. $receive_len = hex(substr($cmd_list[$last_cmd][1],6,2))*2;
  372. }
  373. if ( length($hexline) < $receive_len ){
  374. Log3 $name, 5,"VCONTROL: VCONTROL_Read receive_len < $receive_len, $hexline";
  375. $hash->{PARTIAL} = $hexline;
  376. return"";
  377. }
  378. if ( length($hexline) > $receive_len ){
  379. Log3 $name, 5,"VCONTROL: VCONTROL_Read receive_len > $receive_len, $hexline : Repeat Command";
  380. $hash->{PARTIAL} = "";
  381. $read_now = READ_UNDEF;
  382. return"";
  383. }
  384. }
  385. #exit if no poll period
  386. #exit if no set command send
  387. if ($poll_now == POLL_PAUSED && $send_now == NO_SEND ){
  388. return "";
  389. }
  390. my $sendbuf="";
  391. #End of Poll Interval
  392. if ($poll_now == POLL_ACTIVE && $last_cmd == $cmdcount)
  393. {
  394. $poll_duration = (gettimeofday() - $poll_duration);
  395. my $duration = sprintf("%.2f", $poll_duration);
  396. $hash->{DURATION} = "$duration";
  397. Log3 $name, 4, "VCONTROL: End of Poll ! Duration: $duration";
  398. $poll_now = POLL_PAUSED;
  399. $last_cmd = 0;
  400. @cmd_list = @poll_cmd_list;
  401. $hash->{PARTIAL} = "";
  402. #activate timer get list if questioned
  403. if ($get_timer_now == GET_TIMER_ACTIVE && $send_now == NO_SEND ){
  404. @cmd_list = @get_timer_cmd_list;
  405. Log3 $name, 5, "VCONTROL: Poll TIMER!";
  406. RemoveInternalTimer($hash);
  407. VCONTROL_Poll($hash);
  408. $get_timer_now = GET_TIMER_PAUSED;
  409. }
  410. #reload config file if questioned
  411. if ($get_config_now == GET_CONFIG_ACTIVE ){
  412. VCONTROL_CmdConfig($command_config_file);
  413. @cmd_list = @poll_cmd_list;
  414. $get_config_now = GET_CONFIG_PAUSED;
  415. }
  416. my $closeAfterPoll = AttrVal($name, "closedev", "0");
  417. ###if Attribut to close after poll -> close
  418. if ($closeAfterPoll == 1) {
  419. if ($TCP_CONNECTION == 0) {
  420. ###USB
  421. delete $hash->{USBDev};
  422. delete $hash->{FD};
  423. Log3 $name, 3, "VCONTROL: USB device closed";
  424. }
  425. else {
  426. ###TCP Connection
  427. DevIo_CloseDev($hash);
  428. Log3 $name, 3, "VCONTROL: TCP connection closed";
  429. }
  430. }
  431. return "";
  432. };
  433. #exit if buffer just filled with 0x05 but not for mode (0x05 is a definde mode state)
  434. my $bufflen = length($hexline);
  435. my $buffhalflen = $bufflen/2;
  436. if ( $bufflen > 2 && $hexline =~ /(05){$buffhalflen,}/
  437. && $cmd_list[$last_cmd][2] ne "mode"
  438. && $cmd_list[$last_cmd][2] ne "1ByteU"
  439. && $cmd_list[$last_cmd][2] ne "1ByteU2"
  440. && $cmd_list[$last_cmd][2] ne "1ByteS"
  441. && $cmd_list[$last_cmd][2] ne "1ByteH"
  442. ){
  443. Log3 $name, 5, "VCONTROL: exit if buffer just filled with 0x05";
  444. $hash->{PARTIAL} = "";
  445. $read_now = READ_UNDEF;
  446. return "";
  447. }
  448. #if one 05 received we can send command
  449. if ( length($hexline) == 2 && $hexline eq "05" && $read_now == READ_UNDEF)
  450. {
  451. my $sendstr ="";
  452. #set next poll command
  453. if ($poll_now == POLL_ACTIVE ){
  454. Log3 $name, 5, "VCONTROL: Setze sendstr";
  455. $sendstr = $cmd_list[$last_cmd][1];
  456. }
  457. # no polling active but set command was given
  458. if ($poll_now == POLL_PAUSED && $send_now != NO_SEND ){
  459. $sendstr = $write_cmd_list[$send_now][2]."$send_additonal_param";
  460. }
  461. if ( $sendstr && $sendstr ne "" ){
  462. Log3 $name, 5, "VCONTROL: send '$sendstr'";
  463. $sendbuf = pack('H*', "$sendstr");
  464. #Send on Device
  465. DevIo_SimpleWrite($hash, $sendbuf, 0);
  466. #we have send cmd next receive should be answer
  467. $read_now = READ_ANSWER;
  468. }
  469. else { #wenn wir hier reinrutschen ist etwas mit den listen durcheinander geraten, workaround reset der liste und der commands!
  470. Log3 $name, 5, "VCONTROL: List reset!";
  471. $poll_now = POLL_PAUSED;
  472. $last_cmd = 0;
  473. @cmd_list = @poll_cmd_list;
  474. $hash->{PARTIAL} = "";
  475. $get_timer_now = GET_TIMER_PAUSED;
  476. $get_config_now = GET_CONFIG_PAUSED;
  477. }
  478. }
  479. elsif ( $read_now == READ_ANSWER) #we expect answer on before send command
  480. {
  481. if ($poll_now == POLL_ACTIVE && $hexline ne "05"){
  482. VCONTROL_Parse($hash,$last_cmd,$hexline,0);
  483. $last_cmd++;
  484. $temp_mode = 0;
  485. }
  486. #if the mode is requestet and 0x05 is received
  487. #try again to be sure that 0x05 is not the sync byte
  488. elsif ( $poll_now == POLL_ACTIVE
  489. && substr("$hexline",0,2) eq "05"
  490. && ( $cmd_list[$last_cmd][2] eq "mode"
  491. || $cmd_list[$last_cmd][2] eq "1ByteU"
  492. || $cmd_list[$last_cmd][2] eq "1ByteU2"
  493. || $cmd_list[$last_cmd][2] eq "1ByteS"
  494. || $cmd_list[$last_cmd][2] eq "1ByteH"
  495. )
  496. ){
  497. Log3 $name, 5, "VCONTROL: check temp_mode";
  498. if ($temp_mode < 5){
  499. $temp_mode++;
  500. Log3 $name, 5, "VCONTROL: set temp_mode = $temp_mode";
  501. }
  502. elsif ($temp_mode == 5){
  503. $temp_mode = 0;
  504. VCONTROL_Parse($hash,$last_cmd,$hexline,0);
  505. Log3 $name, 5, "VCONTROL: set mode = ABSCHALT";
  506. $last_cmd++;
  507. }
  508. }
  509. #parse answer on set command
  510. if ($poll_now == POLL_PAUSED && $send_now != NO_SEND ){
  511. VCONTROL_Parse($hash,$send_now,$hexline,1) if ($hexline ne "05");
  512. }
  513. $read_now = READ_UNDEF;
  514. $hash->{PARTIAL} = "";
  515. }
  516. }
  517. #####################################
  518. sub VCONTROL_Parse($$$$)
  519. {
  520. my ($hash, $cmd, $hexline,$answer) = @_;
  521. my $value = "";
  522. my $valuename = "";
  523. my $pn = $hash->{NAME};
  524. if ($answer == 0){
  525. if ($cmd_list[$cmd][2] eq "1ByteU"){
  526. $value = VCONTROL_1ByteUParse(substr($hexline, 0, 2),$cmd_list[$cmd][3]) if (length($hexline) > 1);
  527. } elsif ($cmd_list[$cmd][2] eq "1ByteU2"){
  528. $value = VCONTROL_1ByteU2Parse(substr($hexline, 0, 2),$cmd_list[$cmd][3]) if (length($hexline) > 1);
  529. } elsif ($cmd_list[$cmd][2] eq "1ByteS"){
  530. $value = VCONTROL_1ByteSParse(substr($hexline, 0, 2),$cmd_list[$cmd][3]) if (length($hexline) > 1);
  531. } elsif ($cmd_list[$cmd][2] eq "2ByteS"){
  532. $value = VCONTROL_2ByteSParse($hexline,$cmd_list[$cmd][3]) if (length($hexline) > 3);
  533. } elsif ($cmd_list[$cmd][2] eq "2ByteU"){
  534. $value = VCONTROL_2ByteUParse($hexline,$cmd_list[$cmd][3]) if (length($hexline) > 3);
  535. } elsif ($cmd_list[$cmd][2] eq "1ByteH"){
  536. $value = VCONTROL_1ByteHexParse($hexline) if (length($hexline) > 1);
  537. } elsif ($cmd_list[$cmd][2] eq "2ByteH"){
  538. $value = VCONTROL_2ByteHexParse($hexline) if (length($hexline) > 3);
  539. } elsif ($cmd_list[$cmd][2] eq "2BytePercent"){
  540. $value = VCONTROL_2BytePercentParse($hexline,$cmd_list[$cmd][3]) if (length($hexline) > 1);
  541. } elsif ($cmd_list[$cmd][2] eq "4Byte"){
  542. $value = VCONTROL_4ByteParse($hexline,$cmd_list[$cmd][3]) if (length($hexline) > 7);
  543. } elsif ($cmd_list[$cmd][2] eq "mode"){
  544. $value = VCONTROL_ModeParse($hexline) if (length($hexline) > 1);
  545. } elsif ($cmd_list[$cmd][2] eq "timer"){
  546. $value = VCONTROL_timerParse($hexline) if (length($hexline) > 7);
  547. } elsif ($cmd_list[$cmd][2] eq "date"){
  548. $value = VCONTROL_DateParse($hexline) if (length($hexline) > 7);
  549. }
  550. #this will be the name of the Reading
  551. $valuename = "$cmd_list[$cmd][4]";
  552. Log3 $pn, 5,"VCONTROL: receive '$valuename : $value'";
  553. return $pn if ($value eq "");
  554. if ( $cmd_list[$cmd][2]
  555. && $cmd_list[$cmd][2] ne "mode"
  556. && $cmd_list[$cmd][2] ne "timer"
  557. && $cmd_list[$cmd][3] ne "state"
  558. && $cmd_list[$cmd][3] > 99){
  559. $value = sprintf("%.2f", $value);
  560. }
  561. #TODO config Min and Max Values ????
  562. if ( substr($valuename,0,4) eq "Temp"){
  563. if ( $value < -30 || $value > 199 ){
  564. $value = ReadingsVal($pn,"$valuename",0);
  565. }
  566. }
  567. #get systemtime
  568. my ($sec,$min,$hour,$mday,$mon,$year) = localtime;
  569. $year+=1900;
  570. $mon = $mon+1;
  571. my $plotmonth = $mon;
  572. my $plotmday = $mday;
  573. my $plothour = $hour;
  574. my $plotmin = $min;
  575. my $plotsec = $sec;
  576. if ($mon < 10) {$plotmonth = "0$mon"};
  577. if ($mday < 10) {$plotmday = "0$mday"};
  578. if ($hour < 10) {$plothour = "0$hour"};
  579. if ($min < 10) {$plotmin = "0$min"};
  580. if ($sec < 10) {$plotsec = "0$sec"};
  581. my $systime="$year-$plotmonth-$plotmday"."_"."$plothour:$plotmin:$plotsec";
  582. #Start Update Readings
  583. my $update_only_changes = AttrVal($pn, "update_only_changes", "0");
  584. readingsBeginUpdate ($hash);
  585. if ( $update_only_changes == 0 || ($update_only_changes == 1 && (ReadingsVal($pn,"$valuename",0) ne $value)))
  586. { readingsBulkUpdate ($hash, "$valuename", $value)};
  587. #calculate Kumulation Readings and Day Readings
  588. if ("$cmd_list[$cmd][5]" eq "day" ){
  589. my $start_of_the_day;
  590. if ( $value < 0 ){
  591. $value = ReadingsVal($pn,"$valuename",0);
  592. }
  593. $value = sprintf("%.2f", $value);
  594. $start_of_the_day = ReadingsVal($pn,"$valuename"."DayStart",$value);
  595. my $kumul_day = $value - $start_of_the_day;
  596. $kumul_day = sprintf("%.2f", $kumul_day);
  597. readingsBulkUpdate ($hash, "$valuename"."Today", $kumul_day);
  598. #Next Day for this value is reached
  599. my $debug_day= $DayHash{$valuename};
  600. Log3 $pn, 5, "VCONTROL: DEBUG nextday $mday <-> $debug_day";
  601. if ($mday != $DayHash{$valuename}){
  602. $start_of_the_day = $value;
  603. $start_of_the_day = sprintf("%.2f", $start_of_the_day);
  604. readingsBulkUpdate ($hash, "$valuename"."LastDay" , $kumul_day);
  605. $kumul_day = 0;
  606. $DayHash{$valuename} = $mday;
  607. }
  608. readingsBulkUpdate ($hash, "$valuename"."DayStart" , $start_of_the_day);
  609. }
  610. #if all polling commands are send, update Reading UpdateTime
  611. my $all_cmd = @cmd_list -1;
  612. if ( $cmd == $all_cmd){
  613. readingsBulkUpdate ($hash, "UpdateTime", $systime );
  614. }
  615. #End Update Reading
  616. readingsEndUpdate ($hash, 1);
  617. }
  618. else #answer on set request
  619. {
  620. #Start Poll to refresh readings if send of set request was answered with 00
  621. # and no additional send has to be done
  622. if (substr($hexline, 0, 2) == "00")
  623. {
  624. # it may be configured that another command has to be send
  625. my $next_send = NO_SEND;
  626. foreach(@write_cmd_list) {
  627. if ($$_[0] eq "SET" && $$_[1] eq $write_cmd_list[$send_now][4]){
  628. $next_send=$$_[5];
  629. }
  630. }
  631. if ($next_send == NO_SEND){
  632. #activate timer get list if questioned
  633. if ($get_timer_now == GET_TIMER_ACTIVE ){
  634. @cmd_list = @get_timer_cmd_list;
  635. $get_timer_now = GET_TIMER_PAUSED;
  636. }
  637. if (substr($hexline, 0, 2) == "00"){
  638. Log3 $pn, 5, "VCONTROL: Poll SET!";
  639. RemoveInternalTimer($hash);
  640. VCONTROL_Poll($hash);
  641. }
  642. }
  643. $send_now = $next_send;
  644. }
  645. }
  646. return $pn;
  647. }
  648. #####################################
  649. sub VCONTROL_Ready($)
  650. {
  651. my ($hash) = @_;
  652. my $dev = $hash->{DeviceName};
  653. my $name = $hash->{NAME};
  654. my $po;
  655. if ($TCP_CONNECTION==0) {
  656. ###USB
  657. $po=$hash->{USBDev};
  658. if(!$po) { # Looking for the device
  659. if ($^O=~/Win/) {
  660. $po = new Win32::SerialPort ($dev);
  661. }
  662. else {
  663. $po = new Device::SerialPort ($dev);
  664. }
  665. return undef if(!$po);
  666. Log3 $name, 3, "VCONTROL: USB device $dev reappeared";
  667. $hash->{USBDev} = $po;
  668. if( $^O !~ /Win/ ) {
  669. $hash->{FD} = $po->FILENO;
  670. delete($readyfnlist{"$name.$dev"});
  671. $selectlist{"$name.$dev"} = $hash;
  672. }
  673. else {
  674. $readyfnlist{"$name.$dev"} = $hash;
  675. }
  676. $hash->{PARTIAL} = "";
  677. VCONTROL_DoInit($hash, $po);
  678. DoTrigger($name, "CONNECTED");
  679. $hash->{STATE} = "connected";
  680. }
  681. return undef if !$po;
  682. my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags)=$po->status;
  683. return ($InBytes>0);
  684. }
  685. else {
  686. ###TCP Connection
  687. $hash->{PARTIAL} = "";
  688. return DevIo_OpenDev($hash, 1, "VCONTROL_DoInit") if($hash->{STATE} eq "disconnected");
  689. }
  690. }
  691. #####################################
  692. sub VCONTROL_Set($@)
  693. {
  694. my ($hash, @a) = @_;
  695. my $pn = $hash->{NAME};
  696. my $arg = $a[1];
  697. my $value = (defined $a[2]) ? $a[2] : "";
  698. my $setList = AttrVal($pn, "setList", " ");
  699. #return "Unknown argument ?, choose one of HWW ABSCHALT SPAR-ON SPAR-OFF PARTY-ON PARTY-OFF" if( $arg eq "?");
  700. return "Unknown argument ?, choose one of $setList" if( $arg eq "?");
  701. #needed if cmd in config_file is just a prefix, e.g. set of an timer value
  702. $send_additonal_param="";
  703. #set write commands to send
  704. foreach(@write_cmd_list) {
  705. my $debug_info0=$$_[0];
  706. my $debug_info1=$$_[1];
  707. Log3 $pn, 5, "VCONTROL: DEBUG SET <-> $debug_info0 / $arg <-> $debug_info1";
  708. if ($$_[0] eq "SET" && $$_[1] eq $arg){
  709. $send_now=$$_[5];
  710. if ($$_[3] eq "1ByteU"){
  711. $send_additonal_param=VCONTROL_1ByteUConv($value,$$_[4]);
  712. }
  713. elsif ($$_[3] eq "1ByteS"){
  714. $send_additonal_param=VCONTROL_1ByteSConv($value,$$_[4]);
  715. }
  716. elsif ($$_[3] eq "1ByteUx10"){
  717. $send_additonal_param=VCONTROL_1ByteUx10Conv($value);
  718. }
  719. elsif ($$_[3] eq "2ByteU"){
  720. $send_additonal_param=VCONTROL_2ByteUConv($value,$$_[4]);
  721. }
  722. elsif ($$_[3] eq "2ByteS"){
  723. $send_additonal_param=VCONTROL_2ByteSConv($value,$$_[4]);
  724. }
  725. elsif ($$_[3] eq "date"){
  726. my $strtemp = VCONTROL_DateConv($value);
  727. Log3 $pn, 5, "VCONTROL: DEBUG Timestr: $strtemp";
  728. $send_additonal_param=$strtemp;
  729. }
  730. elsif ($$_[3] eq "timer"){
  731. my $tempday = $$_[4];
  732. $send_additonal_param=VCONTROL_TimerConv($tempday,$value);
  733. @get_timer_cmd_list = @timer_cmd_list;
  734. $get_timer_now = GET_TIMER_ACTIVE;
  735. }
  736. elsif ($$_[3] eq "Register"){
  737. $send_additonal_param=VCONTROL_RegisterConv($value);
  738. if ($send_additonal_param eq "")
  739. {
  740. Log3 $pn, 1, "VCONTROL: Register falsch eingegeben: $value";
  741. return "";
  742. }
  743. else {
  744. Log3 $pn, 1, "VCONTROL: Register gesetzt: $value (01F427$send_additonal_param)";
  745. }
  746. }
  747. return "";
  748. }
  749. }
  750. # possible to correct DayStart Values
  751. if(index($arg,"DayStart") >= 0){
  752. if ( $value ne "" )
  753. {
  754. readingsBeginUpdate ($hash);
  755. readingsBulkUpdate ($hash, $arg, $value);
  756. readingsEndUpdate ($hash, 1);
  757. }
  758. }
  759. #else {
  760. # print "not data_ready: $arg \n";
  761. #}
  762. return "";
  763. }
  764. #####################################
  765. sub VCONTROL_Get($@) {
  766. my ($hash, @a) = @_;
  767. return "no get value specified" if(@a < 2);
  768. my $pn = $hash->{NAME};
  769. my $arg = $a[1];
  770. my $value = (defined $a[2]) ? $a[2] : "";
  771. return "Unknown argument ?, choose one of TIMER CONFIG" if( $arg eq "?");
  772. if ($arg eq "TIMER" )
  773. {
  774. @get_timer_cmd_list = @timer_cmd_list;
  775. }
  776. elsif ($arg eq "CONFIG" )
  777. {
  778. if ($poll_now == POLL_PAUSED ){
  779. VCONTROL_CmdConfig($command_config_file);
  780. @cmd_list = @poll_cmd_list;
  781. }
  782. else {
  783. $get_config_now = GET_CONFIG_ACTIVE;
  784. }
  785. return "";
  786. }
  787. if ($poll_now == POLL_PAUSED ){
  788. @cmd_list = @get_timer_cmd_list;
  789. Log3 $pn, 5, "VCONTROL: Poll GET!";
  790. RemoveInternalTimer($hash);
  791. VCONTROL_Poll($hash);
  792. }
  793. else {
  794. $get_timer_now = GET_TIMER_ACTIVE;
  795. }
  796. return "";
  797. }
  798. #####################################
  799. sub VCONTROL_ReInit($)
  800. {
  801. my $hash = shift;
  802. my $name = $hash->{NAME};
  803. my $dev = $hash->{DeviceName};
  804. delete $hash->{USBDev};
  805. delete $hash->{FD};
  806. DevIo_CloseDev($hash);
  807. $hash->{PARTIAL} = "";
  808. #Opening USB Device
  809. Log3($name, 3, "VCONTROL ReInit VCONTROL device $dev");
  810. if ($TCP_CONNECTION==0) {
  811. ###USB
  812. my $po;
  813. if ($^O=~/Win/) {
  814. require Win32::SerialPort;
  815. $po = new Win32::SerialPort ($dev);
  816. }
  817. else {
  818. require Device::SerialPort;
  819. $po = new Device::SerialPort ($dev);
  820. }
  821. if(!$po) {
  822. my $msg = "Can't open $dev: $!";
  823. Log3($name, 3, $msg) if($hash->{MOBILE});
  824. return $msg if(!$hash->{MOBILE});
  825. $readyfnlist{"$name.$dev"} = $hash;
  826. return undef;
  827. }
  828. Log3($name, 3, "VCONTROL opened VCONTROL device $dev");
  829. $hash->{USBDev} = $po;
  830. if( $^O =~ /Win/ ) {
  831. $readyfnlist{"$name.$dev"} = $hash;
  832. }
  833. else {
  834. $hash->{FD} = $po->FILENO;
  835. delete($readyfnlist{"$name.$dev"});
  836. $selectlist{"$name.$dev"} = $hash;
  837. }
  838. #Initialize to be able to receive data
  839. VCONTROL_DoInit($hash, $po);
  840. }
  841. else {
  842. ###TCP COnnection
  843. DevIo_OpenDev($hash, 0, "VCONTROL_DoInit");
  844. }
  845. }
  846. #####################################
  847. #####################################
  848. ## Load Config
  849. #####################################
  850. #####################################
  851. sub VCONTROL_CmdConfig($)
  852. {
  853. my $cmd_config_file = shift;
  854. my ($sec,$min,$hour,$mday,$mon,$year) = localtime;
  855. my $write_idx=0;
  856. Log3 undef, 3, "VCONTROL: open DATEI '$cmd_config_file'";
  857. open(CMDDATEI,"<$cmd_config_file") || die "problem opening $cmd_config_file\n" ;
  858. undef @poll_cmd_list;
  859. undef @write_cmd_list;
  860. undef @timer_cmd_list;
  861. # undef @timer_ww_cmd_list;
  862. $viess_protocol = PROTOCOL_KW;
  863. while(<CMDDATEI>){
  864. my $zeile=trim($_);
  865. Log3 undef, 5, "VCONTROL: CmdConfig-Zeile $zeile";
  866. if ( length($zeile) > 0 && substr($zeile,0,1) ne "#")
  867. {
  868. my @cfgarray = split(",",$zeile);
  869. foreach(@cfgarray) {
  870. $_ = trim($_);
  871. }
  872. if ($cfgarray[0] eq "PROTOCOL"){
  873. if ( $cfgarray[1] eq "GWG" ){
  874. $viess_protocol = PROTOCOL_GWG;
  875. }
  876. elsif ( $cfgarray[1] eq "300" ){
  877. $viess_protocol = PROTOCOL_300;
  878. }
  879. }
  880. #TODO: CHECK IF CONFIG PARAMS are allowed!!!
  881. elsif ($cfgarray[0] eq "POLL"){
  882. if ( $cfgarray[2] ne "1ByteU"
  883. && $cfgarray[2] ne "1ByteU2"
  884. && $cfgarray[2] ne "1ByteS"
  885. && $cfgarray[2] ne "2ByteS"
  886. && $cfgarray[2] ne "2ByteU"
  887. && $cfgarray[2] ne "1ByteH"
  888. && $cfgarray[2] ne "2ByteH"
  889. && $cfgarray[2] ne "2BytePercent"
  890. && $cfgarray[2] ne "4Byte"
  891. && $cfgarray[2] ne "mode"
  892. && $cfgarray[2] ne "date"
  893. && $cfgarray[2] ne "timer"
  894. ){
  895. Log3 undef, 3, "VCONTROL: unknown parse method '$cfgarray[2]' in '$cmd_config_file'";
  896. }
  897. elsif( (($viess_protocol == PROTOCOL_KW) && (index($cfgarray[1],"01F7") == -1 || length($cfgarray[1]) < 10 ))
  898. || (($viess_protocol == PROTOCOL_GWG) && (index($cfgarray[1],"01CB") == -1 || length($cfgarray[1]) < 10 ))
  899. )
  900. {
  901. Log3 undef, 3, "VCONTROL: wrong Address '$cfgarray[1]' in '$cmd_config_file'";
  902. }
  903. else {
  904. if ($cfgarray[2] eq "timer")
  905. {
  906. my @timercmd = ($cfgarray[0],$cfgarray[1],$cfgarray[2],$cfgarray[3],$cfgarray[4],$cfgarray[5]);
  907. push(@timer_cmd_list,\@timercmd);
  908. }
  909. else {
  910. my @pollcmd = ($cfgarray[0],$cfgarray[1],$cfgarray[2],$cfgarray[3],$cfgarray[4],$cfgarray[5]);
  911. push(@poll_cmd_list,\@pollcmd);
  912. if ("$cfgarray[5]" eq "day"){
  913. $DayHash{$cfgarray[4]} = $mday;
  914. }
  915. }
  916. }
  917. }
  918. elsif ($cfgarray[0] eq "SET"){
  919. if ($cfgarray[3] eq "timer")
  920. {
  921. if ( $cfgarray[4] ne "MO"
  922. && $cfgarray[4] ne "DI"
  923. && $cfgarray[4] ne "MI"
  924. && $cfgarray[4] ne "DO"
  925. && $cfgarray[4] ne "FR"
  926. && $cfgarray[4] ne "SA"
  927. && $cfgarray[4] ne "SO"
  928. )
  929. { Log3 undef, 1, "VCONTROL: wrong Day '$cfgarray[4]' in '$cmd_config_file'";
  930. }
  931. else {
  932. my @setcmd = ($cfgarray[0],$cfgarray[1],$cfgarray[2],$cfgarray[3],$cfgarray[4],$write_idx);
  933. push(@write_cmd_list,\@setcmd);
  934. $write_idx++;
  935. }
  936. }
  937. else {
  938. my @setcmd = ($cfgarray[0],$cfgarray[1],$cfgarray[2],$cfgarray[3],$cfgarray[4],$write_idx);
  939. push(@write_cmd_list,\@setcmd);
  940. $write_idx++;
  941. }
  942. }
  943. else {
  944. Log3 undef, 3, "VCONTROL: unknown command '$cfgarray[0]' in '$cmd_config_file'";
  945. }
  946. }
  947. };
  948. close (CMDDATEI);
  949. Log3 undef, 3, "VCONTROL: DATEI '$cmd_config_file' refreshed";
  950. }
  951. ###########################################################################
  952. ###########################################################################
  953. ### PARSE ROUTINES
  954. ###########################################################################
  955. ###########################################################################
  956. sub VCONTROL_1ByteUParse($$)
  957. {
  958. my $hexvalue = shift;
  959. my $divisor = shift;
  960. my $retstr="";
  961. if (!$divisor || length($divisor) == 0 || $divisor eq "state"){
  962. $retstr = ($hexvalue eq "00") ? "off" : "on";
  963. }
  964. else{
  965. #check if divisor is numeric and not 0
  966. if ( $divisor =~ /^\d+$/ && $divisor != 0){
  967. $retstr = hex($hexvalue)/$divisor;
  968. }
  969. else {
  970. Log3 undef, 3, "VCONTROL: divisor not numeric '$divisor' or 0, it will be ignored";
  971. $retstr = hex($hexvalue)
  972. }
  973. }
  974. return $retstr;
  975. }
  976. #####################################
  977. sub VCONTROL_1ByteU2Parse($$)
  978. {
  979. my $hexvalue = shift;
  980. my $divisor = shift;
  981. return hex(substr($hexvalue,0,2))/$divisor;
  982. }
  983. #####################################
  984. sub VCONTROL_1ByteSParse($$)
  985. {
  986. my $hexvalue = shift;
  987. my $divisor = shift;
  988. return unpack('c', pack('C',hex(substr($hexvalue,0,2))))/$divisor;
  989. }
  990. #####################################
  991. sub VCONTROL_1ByteHexParse($)
  992. {
  993. my $hexvalue = shift;
  994. return (substr($hexvalue,0,2));
  995. }
  996. #####################################
  997. sub VCONTROL_2ByteUParse($$)
  998. {
  999. my $hexvalue = shift;
  1000. my $divisor = shift;
  1001. return hex(substr($hexvalue,2,2).substr($hexvalue,0,2))/$divisor;
  1002. }
  1003. #####################################
  1004. sub VCONTROL_2ByteSParse($$)
  1005. {
  1006. my $hexvalue = shift;
  1007. my $divisor = shift;
  1008. return unpack('s', pack('S',hex(substr($hexvalue,2,2).substr($hexvalue,0,2))))/$divisor;
  1009. }
  1010. #####################################
  1011. sub VCONTROL_2BytePercentParse($$)
  1012. {
  1013. my $hexvalue = shift;
  1014. my $divisor = shift;
  1015. return hex(substr($hexvalue,2,2))/$divisor;
  1016. }
  1017. #####################################
  1018. sub VCONTROL_2ByteHexParse($)
  1019. {
  1020. my $hexvalue = shift;
  1021. return (substr($hexvalue,0,2).substr($hexvalue,2,2));
  1022. }
  1023. #####################################
  1024. sub VCONTROL_4ByteParse($$)
  1025. {
  1026. my $hexvalue = shift;
  1027. my $divisor = shift;
  1028. return hex(substr($hexvalue,6,2).substr($hexvalue,4,2).substr($hexvalue,2,2).substr($hexvalue,0,2))/$divisor;
  1029. }
  1030. #####################################
  1031. sub VCONTROL_ModeParse($)
  1032. {
  1033. my $index = hex(shift);
  1034. return "$mode[$index]" if ($mode[$index]);
  1035. return "";
  1036. }
  1037. #####################################
  1038. sub VCONTROL_timerParse($)
  1039. {
  1040. my $binvalue = shift;
  1041. $binvalue = pack('H*', "$binvalue");
  1042. my ($h1,$h2,$h3,$h4,$h5,$h6,$h7,$h8) = unpack ("CCCCCCCC",$binvalue);
  1043. my @bytes = ($h1,$h2,$h3,$h4,$h5,$h6,$h7,$h8);
  1044. my $timer_str;
  1045. for ( $a = 0; $a < 8; $a = $a+1){
  1046. my $delim = "-";
  1047. if ( $a % 2 ){
  1048. $delim = "/";
  1049. }
  1050. my $byte = $bytes[$a];
  1051. if ($byte == 0xff){
  1052. $timer_str = $timer_str."--$delim";
  1053. }
  1054. else{
  1055. my $hour = ($byte & 0xF8)>>3;
  1056. my $min = ($byte & 7)*10;
  1057. $hour = "0$hour" if ( $hour < 10 );
  1058. $min = "0$min" if ( $min < 10 );
  1059. $timer_str = $timer_str."$hour:$min$delim";
  1060. }
  1061. }
  1062. return "$timer_str";
  1063. }
  1064. #####################################
  1065. sub VCONTROL_DateParse($){
  1066. my $hexvalue = shift;
  1067. my $vcday;
  1068. #0011223344556677
  1069. #01 23 45 67 89 01 23 45
  1070. $vcday = "So" if ( substr($hexvalue,8,2) eq "00" );
  1071. $vcday = "Mo" if ( substr($hexvalue,8,2) eq "01" );
  1072. $vcday = "Di" if ( substr($hexvalue,8,2) eq "02" );
  1073. $vcday = "Mi" if ( substr($hexvalue,8,2) eq "03" );
  1074. $vcday = "Do" if ( substr($hexvalue,8,2) eq "04" );
  1075. $vcday = "Fr" if ( substr($hexvalue,8,2) eq "05" );
  1076. $vcday = "Sa" if ( substr($hexvalue,8,2) eq "06" );
  1077. $vcday = "So" if ( substr($hexvalue,8,2) eq "07" );
  1078. return $vcday.",".substr($hexvalue,6,2).".".substr($hexvalue,4,2).".".substr($hexvalue,0,4)." ".substr($hexvalue,10,2).":".substr($hexvalue,12,2).":".substr($hexvalue,14,2);
  1079. }
  1080. ###########################################################################
  1081. ###########################################################################
  1082. ## CONV ROUTINES
  1083. ###########################################################################
  1084. ###########################################################################
  1085. sub VCONTROL_1ByteUConv($$)
  1086. {
  1087. my $convvalue = shift;
  1088. my $multiplicator = shift;
  1089. if ( $multiplicator =~ /^\d+$/) {
  1090. return (sprintf "%02X", $convvalue*$multiplicator);
  1091. }
  1092. else
  1093. { return (sprintf "%02X", $convvalue); }
  1094. }
  1095. #####################################
  1096. sub VCONTROL_1ByteSConv($$)
  1097. {
  1098. my $convvalue = shift;
  1099. my $multiplicator = shift;
  1100. my $cnvstrvalue;
  1101. if ( $multiplicator =~ /^\d+$/) {
  1102. $cnvstrvalue = (sprintf "%02X", $convvalue*$multiplicator);
  1103. }
  1104. else
  1105. {$cnvstrvalue = (sprintf "%02X", $convvalue);}
  1106. if ($convvalue <0){
  1107. return substr($cnvstrvalue,length($cnvstrvalue)-2,2);
  1108. }
  1109. else {
  1110. return $cnvstrvalue;
  1111. }
  1112. }
  1113. #####################################
  1114. sub VCONTROL_1ByteUx10Conv($)
  1115. {
  1116. my $convvalue = shift;
  1117. return (sprintf "%02X", $convvalue*10);
  1118. }
  1119. #####################################
  1120. sub VCONTROL_2ByteUConv($$)
  1121. {
  1122. my $convvalue = shift;
  1123. my $multiplicator = shift;
  1124. my $hexstr;
  1125. if ( $multiplicator =~ /^\d+$/) {
  1126. $hexstr = (sprintf "%04X", $convvalue*$multiplicator);
  1127. }
  1128. else {
  1129. $hexstr = (sprintf "%04X", $convvalue);
  1130. }
  1131. return substr($hexstr,2,2).substr($hexstr,0,2);
  1132. }
  1133. #####################################
  1134. sub VCONTROL_2ByteSConv($$)
  1135. {
  1136. my $convvalue = shift;
  1137. my $multiplicator = shift;
  1138. my $cnvstrvalue;
  1139. if ( $multiplicator =~ /^\d+$/) {
  1140. $cnvstrvalue = (sprintf "%04X", $convvalue*$multiplicator);
  1141. }
  1142. else {
  1143. $cnvstrvalue = (sprintf "%04X", $convvalue);
  1144. }
  1145. if ($convvalue <0){
  1146. return substr($cnvstrvalue,6,2).substr($cnvstrvalue,4,2);
  1147. }
  1148. else {
  1149. return substr($cnvstrvalue,2,2).substr($cnvstrvalue,0,2);
  1150. }
  1151. }
  1152. #####################################
  1153. sub VCONTROL_DateConv($){
  1154. #Eingabe
  1155. #dd.mm.yyyy_hh:mm:ss
  1156. #Ziel
  1157. #yyyymmddwwhhmmss
  1158. #dd.mm.yyyy
  1159. my $date = shift;
  1160. my $vcday = substr($date,0,2);
  1161. my $vcmonth = substr($date,3,2);
  1162. my $vcyear = substr($date,6,4);
  1163. #hh:mm:ss
  1164. my $vchour = substr($date,11,2);
  1165. my $vcmin = substr($date,14,2);
  1166. my $vcsec = substr($date,17,2);
  1167. my $wday;
  1168. my $tmp;
  1169. my $hlptime = timelocal($vcsec, $vcmin, $vchour, $vcday, $vcmonth -1 , $vcyear - 1900);
  1170. ($tmp, $tmp, $tmp, $tmp, $tmp, $tmp, $wday) = localtime $hlptime;
  1171. my @Wochentage = ("00","01","02","03","04","05","06");
  1172. $wday = $Wochentage[$wday];
  1173. #0011223344556677
  1174. #01 23 45 67 89 01 23 45
  1175. return $vcyear.$vcmonth.$vcday.$wday.$vchour.$vcmin.$vcsec;
  1176. }
  1177. #####################################
  1178. sub VCONTROL_TimerConv($$){
  1179. my $timer_day = shift;
  1180. my $value = shift;
  1181. my @timerarray = split(",",$value);
  1182. return "" if (@timerarray != 8);
  1183. my @hextimerdata;
  1184. foreach(@timerarray) {
  1185. if ($_ eq "--"){
  1186. push(@hextimerdata,"FF");
  1187. }
  1188. else{
  1189. my ($timerhour, $timermin) = split(":",$_,2);
  1190. if (length($timerhour) != 2 || length($timermin) != 2 ){
  1191. {return "";}
  1192. }
  1193. if ( $timerhour < "00" || $timerhour > "24" ){
  1194. {return "";}
  1195. }
  1196. if ( $timermin ne "00" && $timermin ne "10" && $timermin ne "20" && $timermin ne "30" && $timermin ne "40" && $timermin ne "50"){
  1197. {return "";}
  1198. }
  1199. my $helpvalue = (($timerhour <<3) + ($timermin/10)) & 0xff;
  1200. push(@hextimerdata, (sprintf "%02X", $helpvalue));
  1201. }
  1202. }
  1203. my $suffix="";
  1204. foreach (@hextimerdata){
  1205. $suffix = "$suffix"."$_";
  1206. }
  1207. return $suffix;
  1208. }
  1209. #####################################
  1210. sub VCONTROL_RegisterConv($)
  1211. {
  1212. my $convvalue = shift;
  1213. if (length($convvalue)==4 || (length($convvalue)==5 && substr($convvalue,2,1)eq"-"))
  1214. {
  1215. my $register=substr($convvalue,0,2);
  1216. my $value=substr($convvalue,2,3);
  1217. my $hexvalue=sprintf "%02X", $value;
  1218. if ($value <0)
  1219. {
  1220. $hexvalue = substr($hexvalue,length($hexvalue)-2,2);
  1221. }
  1222. return $register."01".$hexvalue;
  1223. }
  1224. else
  1225. {
  1226. return "";
  1227. }
  1228. }
  1229. 1;
  1230. =pod
  1231. =begin html
  1232. <a name="VCONTROL"></a>
  1233. <h3>VCONTROL</h3>
  1234. <ul>
  1235. VCONTROL is a fhem-Modul to control and read information from a VIESSMANN heating via Optolink-adapter.<br><br>
  1236. An Optolink-Adapter is necessary (USB or LAN), you will find information here:<br>
  1237. <a href="http://openv.wikispaces.com/">http://openv.wikispaces.com/</a><br><br>
  1238. Additionaly you need to know Memory-Adresses for the div. heating types (e.g. V200KW1, VScotHO1, VPlusHO1 ....),<br>
  1239. that will be read by the module to get the measurements or to set the actual state.<br>
  1240. Additional information you will find in the forum <a href="http://forum.fhem.de/index.php/topic,20280.0.html">http://forum.fhem.de/index.php/topic,20280.0.html</a> und auf der wiki Seite <a href="http://www.fhemwiki.de/wiki/Vitotronic_200_%28Viessmann_Heizungssteuerung%29">http://www.fhemwiki.de/wiki/Vitotronic_200_%28Viessmann_Heizungssteuerung%29</a><br><br><br>
  1241. <a name="VCONTROLdefine"><b>Define</b></a>
  1242. <ul>
  1243. <code>define &lt;name&gt; VCONTROL &lt;serial-device/LAN-Device:port&gt; &lt;configfile&gt; [&lt;intervall&gt;] </code><br>
  1244. <br>
  1245. <li><b>&lt;serial-device/LAN-Device:port&gt;</b><br>
  1246. USB Port (e.g. com4, /dev/ttyUSB3) or TCPIP:portnumber<br>
  1247. </li>
  1248. <li><b>&lt;intervall&gt;</b><br>
  1249. Poll Intervall in seconds (default 180)<br>
  1250. </li>
  1251. <li><b>&lt;configfile&gt;</b><br>
  1252. path to the configuration file, containing the memory addresses<br>
  1253. </li>
  1254. <br>
  1255. Example:<br><br>
  1256. serial device com4, every 3 minutes will be polled, configuration file name is 99_VCONTROL.cfg, existing in the fhem root directory<br><br>
  1257. Windows:<br>
  1258. define Heizung VCONTROL com4 99_VCONTROL.cfg 180<br><br>
  1259. Linux:<br>
  1260. define Heizung VCONTROL /dev/ttyUSB3 99_VCONTROL.cfg 180<br>
  1261. </ul>
  1262. <br><br>
  1263. <a name="VCONTROLset"><b>Set</b></a>
  1264. <ul>
  1265. These commands will be configured in the configuartion file.
  1266. </ul>
  1267. <br><br>
  1268. <a name="VCONTROLget"><b>Get</b></a>
  1269. <ul>
  1270. get &lt;name&gt; CONFIG<br><br>
  1271. reload the module specific configfile<br><br>
  1272. More commands will be configured in the configuration file.
  1273. </ul>
  1274. <br><br>
  1275. <a name="VCONTROLparameter"><b>configfile</b></a>
  1276. <ul>
  1277. You will find example configuration files for the heating types V200KW1, VScotHO1, VPlusHO1 on the wiki page <a href="http://www.fhemwiki.de/wiki/Vitotronic_200_%28Viessmann_Heizungssteuerung%29">http://www.fhemwiki.de/wiki/Vitotronic_200_%28Viessmann_Heizungssteuerung%29</a>.<br><br>
  1278. The lines of the configuration file can have the following structure:<br><br>
  1279. <li>lines beginning with "#" are comments!<br></li>
  1280. <li>Polling Commands (POLL) to read values.<br></li>
  1281. <li>Set Commands (SET) to set values.<br></li>
  1282. <br>
  1283. <b>Polling Commands have the following structure:<br><br></b>
  1284. POLL, ADDRESSE, PARSEMETHODE, DIVISOR, READING-NAME, KUMULATION<br><br>
  1285. <ul>
  1286. <li><b>POLL</b><br>
  1287. is fix POLL<br>
  1288. </li>
  1289. <br>
  1290. <li><b>ADDRESSE</b><br>
  1291. Memory Address leading to the value, the will be read in the memory on the heating.<br>
  1292. It is subdivided in 3 parts:<br>
  1293. <ul>
  1294. <li> Beginning is fix 01F7 (defines a reading command)</li>
  1295. <li> followed by actuak address<br></li>
  1296. <li> followed by number of Bytes to be read.<br></li>
  1297. </ul>
  1298. </li>
  1299. <br>
  1300. <li><b>PARSEMETHODE</b><br>
  1301. Method how to parse the read bytes.<br>
  1302. methods so far:<br>
  1303. <ul>
  1304. <li>1ByteU :<br> Read value is 1 Byte without algebraic sign (if column Divisor set to state -> only 0 / 1 or off / on)<br></li>
  1305. <li>1ByteS :<br> Read value is 1 Byte with algebraic sign (wenn Spalte Divisor state ist -> nur 0 / 1 also off / on)<br></li>
  1306. <li>2ByteS :<br> Read value is 2 Byte with algebraic sign<br></li>
  1307. <li>2ByteU :<br> Read value is 2 Byte without algebraic sign<br></li>
  1308. <li>2BytePercent :<br> Read value is 2 Byte in percent<br></li>
  1309. <li>4Byte :<br> Read value is 4 Byte<br></li>
  1310. <li>mode :<br> Read value is the actual operating status<br></li>
  1311. <li>timer :<br> Read value is an 8 Byte timer value<br></li>
  1312. <li>date :<br> Read value is an 8 Byte timestamp<br></li>
  1313. POLL Commands unsing the method timer will not be polled permanent, they have to be read by a GET Commando explicitly.<br>
  1314. GET &lt;devicename&gt; TIMER<br>
  1315. </ul>
  1316. </li>
  1317. <br>
  1318. <li><b>DIVISOR</b><br>
  1319. If the parsed value is multiplied by a factor, you can configure a divisor.<br>
  1320. Additionally for values, that just deliver 0 or 1, you can configure state in this column.<br>
  1321. This will force the reading to off and on, instead of 0 and 1.<br>
  1322. </li>
  1323. <br>
  1324. <li><b>READING-NAME</b><br>
  1325. The read and parsed value will be stored in a reading with this name in the device.
  1326. </li>
  1327. <br>
  1328. <li><b>KUMULATION</b><br>
  1329. Accumulated Day values will be automatically stored for polling commands with the value day in the column KUMULATION.<br>
  1330. Futhermore there will be stored the values of the last day in additional readings after 00:00.<br>
  1331. So you have the chance to plot daily values.<br>
  1332. The reading names will be supplemented by DayStart, Today and LastDay!<br>
  1333. </li>
  1334. <br>
  1335. Examples:<br><br>
  1336. <code>POLL, 01F7080402, 2ByteS, 10 , Temp-WarmWater-Actual , -<br></code>
  1337. <code>POLL, 01F7088A02, 2ByteU, 1 , BurnerStarts , day<br></code>
  1338. </ul>
  1339. <br><br>
  1340. <b>Set Commands have the following structure:<br><br></b>
  1341. SET,SETCMD, ADRESSE, CONVMETHODE, NEXT_CMD or DAY for timer<br><br>
  1342. <ul>
  1343. <li><b>SET</b><br>
  1344. is fix SET<br>
  1345. </li>
  1346. <br>
  1347. <li><b>SETCMD</b><br>
  1348. SETCMD are commands that will be used in FHEM to set a value of a device<br>
  1349. set &lt;devicename&gt; &lt;setcmd&gt;<br>
  1350. e.g. SET &lt;devicename&gt; WW to set the actual operational status to Warm Water processing<br>
  1351. </li>
  1352. <br>
  1353. <li><b>ADDRESSE</b><br>
  1354. Memory Address where the value has to be written in the memory of the heating.<br>
  1355. It is subdivided in 4 parts:<br>
  1356. <ul>
  1357. <li> Beginning is fix 01F4 (defines a writing command)</li>
  1358. <li> followed by actual address<br></li>
  1359. <li> followed by number of data-bytes to be written<br></li>
  1360. <li> followed by the data-bytes themselves<br></li>
  1361. </ul>
  1362. <br>
  1363. There are two Address versions:<br>
  1364. <li>Version 1: Value to be set is fix, e.g. Spar Mode on is fix 01<br></li>
  1365. <li>Version 2: Value has to be passed, e.g. warm water temperature<br></li>
  1366. </li>
  1367. <br>
  1368. <li><b>CONVMETHODE</b><br>
  1369. Method how to convert the value with Version 2 in Bytes.<br>
  1370. For Version 1 you can use - here.<br>
  1371. Methods so far:<br>
  1372. <ul>
  1373. <li>1ByteU :<br> Value to be written in 1 Byte without algebraic sign<br>with Version 2 it has to be a number<br></li>
  1374. <li>1ByteS :<br> Value to be written in 1 Byte with algebraic sign<br>with Version 2 it has to be a number<br></li>
  1375. <li>2ByteS :<br> Value to be written in 2 Byte with algebraic sign<br>with Version 2 it has to be a number<br></li>
  1376. <li>2ByteU :<br> Value to be written in 2 Byte without algebraic sign<br>with Version 2 it has to be a number<br></li>
  1377. <li>timer :<br> Value to be written is an 8 Byte Timer value<br>with Version 2 it has to be a string with this structure:<br>
  1378. 8 times of day comma separeted. (ON1,OFF1,ON2,OFF2,ON3,OFF3,ON4,OFF4)<br>
  1379. no time needed ha to be specified with -- .<br>
  1380. Minutes of the times are just allowed to thi values: 00,10,20,30,40 or 50<br>
  1381. Example: 06:10,12:00,16:00,23:00,--,--,--,--</li>
  1382. <li>date :<br> Value to be written is an 8 Byte timestamp<br>with Version 2 it has to be a string with this structure:<br>
  1383. format specified is DD.MM.YYYY_HH:MM:SS<br>
  1384. Example: 21.03.2014_21:35:00</li>
  1385. </ul>
  1386. </li>
  1387. <br>
  1388. <li><b>NEXT_CMD or DAY</b><br>
  1389. This column has three functions:
  1390. <ul>
  1391. <li> If this columns is configured with a name of another SETCMD, it will be processed directly afterwards.<br>
  1392. Example: after setting Spar Mode on (S-ON), you have to set Party Mode off (P-OFF) <br></li>
  1393. <li> Using a CONVMETHODE 1ByteU or 1ByteS or 2ByteS or 2ByteU , you can use the column as an multiplicator,<br>
  1394. which will be multiplied to the value in the SET command<br>
  1395. Example: <code>SET, TEMPNHK1 , 01F4200002 , 2ByteU , 10</code>
  1396. With <code>SET DEVICE TEMPNHK1 21</code> 210 will be send to the heating.
  1397. </li>
  1398. <li>Using timer as CONVMETHODE, so it has to be specified a week day in this columns.<br>
  1399. possible values: MO DI MI DO FR SA SO<br></li>
  1400. </li>
  1401. <br>
  1402. </ul>
  1403. Examples:<br><br>
  1404. <code>SET, WW , 01F423010100, state , -<br></code>
  1405. <code>SET, S-ON , 01F423020101, state_spar , P-OFF<br></code>
  1406. <code>SET, WWTEMP , 01F4630001 , 1ByteU , -<br></code>
  1407. <code>SET, TIMER_2_MO, 01F4200008 , timer , MO<br></code>
  1408. </ul>
  1409. </ul>
  1410. <br>
  1411. <a name="VCONTROLreadings"><b>Readings</b></a>
  1412. <ul>The values read will be stored in readings, that will be configured as described above.</ul>
  1413. </ul>
  1414. =end html
  1415. =begin html_DE
  1416. <a name="VCONTROL"></a>
  1417. <h3>VCONTROL</h3>
  1418. <ul>
  1419. Das VCONTROL ist das fhem-Modul eine VIESSMANN Heizung via Optolink-Schnittstelle auszulesen und zu steuern.<br><br>
  1420. Notwendig ist dazu ein Optolink-Adapter (USB oder LAN), zu dem hier Informationen zu finden sind:<br>
  1421. <a href="http://http://openv.wikispaces.com/">http://openv.wikispaces.com/</a><br><br>
  1422. Zus&auml;tzlich m&uuml;ssen f&uuml;r die verschiedenen Heizungstypen (z.B. V200KW1, VScotHO1, VPlusHO1 ....) Speicher-Adressen bekannt sein,<br>
  1423. unter denen die Messwerte abgefragt oder aber auch Stati gesetzt werden k&ouml;nnen.<br>
  1424. Informationen hierzu findet man im Forum <a href="http://http://openv.wikispaces.com/">http://openv.wikispaces.com/</a> und auf der wiki Seite <a href="http://http://openv.wikispaces.com/">http://openv.wikispaces.com/</a><br><br><br>
  1425. <a name="VCONTROLdefine"><b>Define</b></a>
  1426. <ul>
  1427. <code>define &lt;name&gt; VCONTROL &lt;serial-device/LAN-Device:port&gt; &lt;configfile&gt; [&lt;intervall&gt;] </code><br>
  1428. <br>
  1429. <li><b>&lt;serial-device/LAN-Device:port&gt;</b><br>
  1430. USB Port (z.B. com4, /dev/ttyUSB3) oder aber TCPIP:portnummer<br>
  1431. </li>
  1432. <li><b>&lt;intervall&gt;</b><br>
  1433. Anzahl Sekunden wie oft die Heizung ausgelesen werden soll (default 180)<br>
  1434. </li>
  1435. <li><b>&lt;configfile&gt;</b><br>
  1436. Pfad wo die Konfigurationsdatei f&uuml;r das Modul zu finden ist, die die Adressen beinhaltet<br>
  1437. </li>
  1438. <br>
  1439. Beispiel:<br><br>
  1440. serielle Schnittstelle &uuml;ber com4, alle 3 Minuten wird gepollt, configfile heisst 99_VCONTROL.cfg und liegt im fhem root Verzeichnis<br><br>
  1441. Windows:<br>
  1442. define Heizung VCONTROL com4 99_VCONTROL.cfg 180<br><br>
  1443. Linux:<br>
  1444. define Heizung VCONTROL /dev/ttyUSB3 99_VCONTROL.cfg 180<br>
  1445. </ul>
  1446. <br><br>
  1447. <a name="VCONTROLset"><b>Set</b></a>
  1448. <ul>
  1449. Diese m&uuml;ssen &uuml;ber das configfile konfiguriert werden.
  1450. </ul>
  1451. <br><br>
  1452. <a name="VCONTROLget"><b>Get</b></a>
  1453. <ul>
  1454. get &lt;name&gt; CONFIG<br><br>
  1455. Mit diesem Befehl wird das Modul spezifische configfile nachgeladen.<br><br>
  1456. Diese anderen Befehler m&uuml;ssen &uuml;ber das configfile konfiguriert werden.
  1457. </ul>
  1458. <br><br>
  1459. <a name="VCONTROLparameter"><b>configfile</b></a>
  1460. <ul>
  1461. Im configfile hat man nun die folgenden Konfigurations M&ouml;glichkeiten.<br><br>
  1462. Beispieldateien f&uml;r die Ger&auml;te-Typen V200KW1, VScotHO1, VPlusHO1 sind auf der wiki Seite <a href="http://www.fhemwiki.de/wiki/Vitotronic_200_%28Viessmann_Heizungssteuerung%29">http://www.fhemwiki.de/wiki/Vitotronic_200_%28Viessmann_Heizungssteuerung%29</a> zu finden.<br><br>
  1463. <li>Zeilen die mit "#" beginnen sind Kommentar!<br></li>
  1464. <li>Polling Commandos (POLL) zum Lesen von Werten k&ouml;nnen konfiguriert werden.<br></li>
  1465. <li>Set Commandos (SET) zum setzen von Werten k&ouml;nnen konfiguriert werden.<br></li>
  1466. <br>
  1467. <b>Polling Commandos haben den folgenden Aufbau:<br><br></b>
  1468. POLL, ADDRESSE, PARSEMETHODE, DIVISOR, READING-NAME, KUMULATION<br><br>
  1469. <ul>
  1470. <li><b>POLL</b><br>
  1471. muss fest auf POLL stehen<br>
  1472. </li>
  1473. <br>
  1474. <li><b>ADDRESSE</b><br>
  1475. Adresse, an der der auszulesende Wert im Speicher zu finden ist.<br>
  1476. Sie besteht aus 3 Teilen:<br>
  1477. <ul>
  1478. <li> beginnt immer mit 01F7 (Kommando zum Lesen)</li>
  1479. <li> danach folgt die eigentliche Addresse<br></li>
  1480. <li> danach muss die Anzahl der zu lesenden Bytes noch an die Adresse angehängt werden.<br></li>
  1481. </ul>
  1482. </li>
  1483. <br>
  1484. <li><b>PARSEMETHODE</b><br>
  1485. Methode wie die gelesenen Bytes interpretiert werden m&uuml;ssen.<br>
  1486. Bisher m&ouml;gliche Parsemethoden:<br>
  1487. <ul>
  1488. <li>1ByteU :<br> Empfangener Wert in 1 Byte ohne Vorzeichen (wenn Spalte Divisor state ist -> nur 0 / 1 also off / on)<br></li>
  1489. <li>1ByteU2 :<br> Empfangener Wert in 1 Byte ohne Vorzeichen (wenn Spalte Divisor state ist -> nur 0 / 1 also off / on)<br></li>
  1490. <li>1ByteS :<br> Empfangener Wert in 1 Byte mit Vorzeichen (wenn Spalte Divisor state ist -> nur 0 / 1 also off / on)<br></li>
  1491. <li>2ByteS :<br> Empfangener Wert in 2 Byte mit Vorzeichen<br></li>
  1492. <li>2ByteU :<br> Empfangener Wert in 2 Byte ohne Vorzeichen<br></li>
  1493. <li>2BytePercent :<br> Empfangener Wert in 2 Byte als Prozent Wert<br></li>
  1494. <li>2ByteH :<br> Empfangener Wert in 2 Byte als Hex Wert<br></li>
  1495. <li>4Byte :<br> Empfangener Wert in 4 Byte<br></li>
  1496. <li>mode :<br> Empfangener Wert ist der Betriebsstatus<br></li>
  1497. <li>timer :<br> Empfangener Wert ist ein 8 Byte Timer Werte<br></li>
  1498. <li>date :<br> Empfangener Wert ist ein 8 Byte Zeitstempel<br></li>
  1499. POLL Commandos die die Parsemethode timer enthalten werden nicht ständig gelesen, sondern müssen mit einem GET Commando geholt werden.<br>
  1500. GET &lt;devicename&gt; TIMER<br>
  1501. </ul>
  1502. </li>
  1503. <br>
  1504. <li><b>DIVISOR</b><br>
  1505. Wenn der interpretierte Wert noch um einen Faktor zu hoch ist, kann hier ein Divisor angegeben werden.<br>
  1506. Zus&auml;tzlich hat man hier bei Werten, die nur 0 oder 1 liefern die m&ouml;glich state einzutragen.<br>
  1507. Dies f&uuml;hrt dazu, dass das Reading mit off (0) und on (1) belegt wird, statt mit dem Wert.<br>
  1508. </li>
  1509. <br>
  1510. <li><b>READING-NAME</b><br>
  1511. Der gelesene und interpretierte Wert wird unter diesem Reading abgelegt.
  1512. </li>
  1513. <br>
  1514. <li><b>KUMULATION</b><br>
  1515. Bei den Polling Commandos mit dem Wert day bei der Spalte KUMULATION werden Tageswerte Kumuliert.<br>
  1516. Es werden dann jeweils nach 00:00 Uhr die Werte des letzten Tages ebenfalls als Readings im Device eingetragen,<br>
  1517. so dass man die Werte pro Tag auch plotten oder auswerten kann.<br>
  1518. Beim Readingnamen wird dann jeweils: DayStart,Today und LastDay angehangen!<br>
  1519. </li>
  1520. <br>
  1521. Beispiel:<br><br>
  1522. <code>POLL, 01F7080402, 2ByteS, 10 , Temp-WarmWasser-Ist , -<br></code>
  1523. <code>POLL, 01F7088A02, 2ByteU, 1 , BrennerStarts , day<br></code>
  1524. </ul>
  1525. <br><br>
  1526. <b>Set Commandos haben den folgenden Aufbau:<br><br></b>
  1527. SET,SETCMD, ADRESSE, CONVMETHODE, NEXT_CMD or DAY for timer<br><br>
  1528. <ul>
  1529. <li><b>SET</b><br>
  1530. muss fest auf SET stehen<br>
  1531. </li>
  1532. <br>
  1533. <li><b>SETCMD</b><br>
  1534. Die SETCMD sind die Commandos die man in FHEM zum setzen angeben muss<br>
  1535. set &lt;devicename&gt; &lt;setcmd&gt;<br>
  1536. z.B. SET &lt;devicename&gt; WW zum setzen auf den Status nur Warm Wasser Aufbereitung<br>
  1537. </li>
  1538. <br>
  1539. <li><b>ADDRESSE</b><br>
  1540. Adresse, an der der zu setzende Wert im Speicher zu schreiben ist.<br>
  1541. Sie besteht aus 4 Teilen:<br>
  1542. <ul>
  1543. <li> beginnt immer mit 01F4 (Kommando zum Lesen)</li>
  1544. <li> danach folgt die eigentliche Addresse<br></li>
  1545. <li> danach folgt die Anzahl der zu schreibenden Daten-Bytes<br></li>
  1546. <li> danach m&uuml;ssen die Daten-Bytes selber noch an die Adresse angehängt werden.<br></li>
  1547. </ul>
  1548. <br>
  1549. Es gibt zwei Varianten bei den Adressen:<br>
  1550. <li>Variante 1: Wert steht bereits fest, z.B. Spar Modus einschalten ist fix 01<br></li>
  1551. <li>Variante 2: Wert muss &uumlbergeben werden, z.B. Warm Wasser Temperatur<br></li>
  1552. </li>
  1553. <br>
  1554. <li><b>CONVMETHODE</b><br>
  1555. Methode wie der zu schreibende Wert bei Variante 2 in Bytes konvertiert werden muss.<br>
  1556. Bei Variante 1 kann man - eintragen.<br>
  1557. Bisher m&ouml;gliche Convmethoden:<br>
  1558. <ul>
  1559. <li>1ByteU :<br> Zu sendender Wert in 1 Byte ohne Vorzeichen<br>bei Variante 2 muss eine Zahl &uuml;bergeben werden<br></li>
  1560. <li>1ByteS :<br> Zu sendender Wert in 1 Byte mit Vorzeichen<br>bei Variante 2 muss eine Zahl &uuml;bergeben werden<br></li>
  1561. <li>2ByteS :<br> Zu sendender Wert in 2 Byte mit Vorzeichen<br>bei Variante 2 muss eine Zahl &uuml;bergeben werden<br></li>
  1562. <li>2ByteU :<br> Zu sendender Wert in 2 Byte ohne Vorzeichen<br>bei Variante 2 muss eine Zahl &uuml;bergeben werden<br></li>
  1563. <li>timer :<br> Zu sendender Wert ist ein 8 Byte Timer Werte<br>bei Variante 2 muss folgender String uebergeben werden:<br>
  1564. 8 Uhrzeiten mit Komma getrennt. (AN1,AUS1,AN2,AUS2,AN3,AUS3,AN4,AUS4)<br>
  1565. Keine Uhrzeit muss als -- angegeben werden.<br>
  1566. Minuten der Uhrzeiten dürfen nur 00,10,20,30,40 oder 50 sein<br>
  1567. Beispiel: 06:10,12:00,16:00,23:00,--,--,--,--</li>
  1568. <li>date :<br> Zu sendender Wert ist ein 8 Byte Zeitstempel<br>bei Variante 2 muss folgender String uebergeben werden:<br>
  1569. es muss das Format DD.MM.YYYY_HH:MM:SS eingehalten werden<br>
  1570. Beispiel: 21.03.2014_21:35:00</li>
  1571. </ul>
  1572. </li>
  1573. <br>
  1574. <li><b>NEXT_CMD or DAY</b><br>
  1575. Diese Spalte erf&uuml;llt drei Funktionen:
  1576. <ul>
  1577. <li>Gibt man in dieser Spalte ein anderes konfiguriertes SETCMD an, so wird dies anschließend ausgeführt.<br>
  1578. Beispiel: nach dem Spar Modus (S-ON) gesetzt wurde, muss der Party Modus (P-OFF) ausgeschaltet werden<br>
  1579. </li>
  1580. <li> Ist als CONVMETHODE 1ByteU oder 1ByteS oder 2ByteS oder 2ByteU angegeben, so kann hier ein Faktor angegeben,<br>
  1581. der beim SET auf den angegeben multipliziert wird<br>
  1582. Beispiel: <code>SET, TEMPNHK1 , 01F4200002 , 2ByteU , 10</code>
  1583. Bei <code>SET DEVICE TEMPNHK1 21</code> wird 210 an die Heizung gesendet.
  1584. </li>
  1585. <li>Ist als CONVMETHODE timer angegeben, so muss man in dieser Spalte den Wochentag angeben, für den der Timer gilt.<br>
  1586. M&ouml;gliche Werte: MO DI MI DO FR SA SO<br></li>
  1587. </li>
  1588. <br>
  1589. </ul>
  1590. Beispiele:<br><br>
  1591. <code>SET, WW , 01F423010100, state , -<br></code>
  1592. <code>SET, S-ON , 01F423020101, state_spar , P-OFF<br></code>
  1593. <code>SET, WWTEMP , 01F4630001 , 1ByteU , -<br></code>
  1594. <code>SET, TIMER_2_MO, 01F4200008 , timer , MO<br></code>
  1595. </ul>
  1596. </ul>
  1597. <br>
  1598. <a name="VCONTROLreadings"><b>Readings</b></a>
  1599. <ul>Die eingelesenen Werte werden wie oben beschrieben in selbst konfigurierten Readings abgelegt.</ul>
  1600. </ul>
  1601. =end html_DE
  1602. =cut