95_Babble.pm 88 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257
  1. ########################################################################################
  2. #
  3. # Babble.pm
  4. #
  5. # FHEM module for speech control of FHEM devices
  6. #
  7. # Prof. Dr. Peter A. Henning
  8. #
  9. # $Id: 95_Babble.pm 16371 2018-03-10 09:28:10Z phenning $
  10. #
  11. ########################################################################################
  12. #
  13. # This programm is free software; you can redistribute it and/or modify
  14. # it under the terms of the GNU General Public License as published by
  15. # the Free Software Foundation; either version 2 of the License, or
  16. # (at your option) any later version.
  17. #
  18. # The GNU General Public License can be found at
  19. # http://www.gnu.org/copyleft/gpl.html.
  20. # A copy is found in the textfile GPL.txt and important notices to the license
  21. # from the author is found in LICENSE.txt distributed with these scripts.
  22. #
  23. # This script is distributed in the hope that it will be useful,
  24. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  26. # GNU General Public License for more details.
  27. #
  28. ########################################################################################
  29. package main;
  30. use strict;
  31. use warnings;
  32. use vars qw(%defs); # FHEM device/button definitions
  33. use vars qw(%intAt); # FHEM at definitions
  34. use vars qw($FW_ME);
  35. use JSON; # imports encode_json, decode_json, to_json and from_json.
  36. my $rive = 0;
  37. my $riveinterpreter;
  38. #-- RiveScript missing in System
  39. if (eval {require RiveScript;1;} ne 1) {
  40. Log 1,"[Babble] the RiveScript module is missing from your Perl installation - chatbot functionality not available";
  41. Log 1," check cpan or https://github.com/aichaos/rivescript-perl for download and installation";
  42. } else {
  43. RiveScript->import();
  44. $rive = 1;
  45. Log 1,"[Babble] the RiveScript module has been imported successfully, chatbot functionality available";
  46. }
  47. #########################
  48. # Global variables
  49. my $babblelinkname = "babbles"; # link text
  50. my $babblehiddenroom = "babbleRoom"; # hidden room
  51. my $babblepublicroom = "babble"; # public room
  52. my $babbleversion = "1.32";
  53. my %babble_transtable_EN = (
  54. "ok" => "OK",
  55. "notok" => "Not OK",
  56. "start" => "Start",
  57. "end" => "End",
  58. "add" => "Add",
  59. "added" => "added",
  60. "remove" => "Remove",
  61. "removed" => "removed",
  62. "modify" => "Modify",
  63. "modified" => "modified",
  64. "cancel" => "Cancel",
  65. "status" => "Status",
  66. "notstarted" => "Not started",
  67. "next" => "Next",
  68. "babbledev" => "Babble Devices",
  69. "babbleplaces" => "Babble Places",
  70. "babbleverbs" => "Babble Verbs",
  71. "babblename" => "Babble Name",
  72. "babbletest" => "Babble Test",
  73. "fhemname" => "FHEM Name",
  74. "device" => "Device",
  75. "place" => "Place",
  76. "places" => "Places",
  77. "rooms" => "Rooms",
  78. "verb" => "Verb",
  79. "target" => "Target",
  80. "result" => "Result",
  81. "unknown" => "unknown",
  82. "infinitive" => "Infinitive",
  83. "conjugations" => "Conjugations and Variations",
  84. "helptext" => "Help Text",
  85. "confirm" => "Confirmation",
  86. "speak" => "Please speak",
  87. "followedby" => "followed by",
  88. "placespec" => "a place specification",
  89. "dnu" => "Sorry, I did not understand this",
  90. "input" => "Input",
  91. "test" => "Test",
  92. "exec" => "Execute",
  93. "value" => "Value",
  94. "save" => "Save",
  95. "action" => "Action",
  96. "time" => "Time",
  97. "description" => "Description",
  98. "settings" => "Settings",
  99. "babbles" => "Babble System",
  100. "setparms" => "Set Parameters",
  101. #--
  102. "hallo" => "Hallo",
  103. "state" => "Security",
  104. "unlocked" => "Unlocked",
  105. "locked" => "Locked"
  106. );
  107. my %babble_transtable_DE = (
  108. "ok" => "OK",
  109. "notok" => "Nicht OK",
  110. "start" => "Start",
  111. "end" => "Ende",
  112. "add" => "Hinzufügen",
  113. "added" => "hinzugefügt",
  114. "remove" => "Entfernen",
  115. "removed" => "entfernt",
  116. "modify" => "Ändern",
  117. "modified" => "geändert",
  118. "cancel" => "Abbruch",
  119. "status" => "Status",
  120. "notstarted" => "Nicht gestartet",
  121. "next" => "Nächste",
  122. "babbledev" => "Babble Devices",
  123. "babbleplaces" => "Babble Orte",
  124. "babbleverbs" => "Babble Verben",
  125. "babblename" => "Babble Name",
  126. "babbletest" => "Babble Test",
  127. "fhemname" => "FHEM Name",
  128. "device" => "Gerät",
  129. "place" => "Ort",
  130. "places" => "Orte",
  131. "rooms" => "Räume",
  132. "verb" => "Verb",
  133. "target" => "Ziel",
  134. "result" => "Ergebnis",
  135. "unknown" => "unbekannt",
  136. "infinitive" => "Infinitiv",
  137. "conjugations" => "Konjugationen und Variationen",
  138. "helptext" => "Hilfetext",
  139. "confirm" => "Bestätigung",
  140. "speak" => "Bitte sprich",
  141. "followedby" => "gefolgt von",
  142. "placespec" => "einer Ortsangabe",
  143. "dnu" => "Es tut mir leid, das habe ich nicht verstanden",
  144. "input" => "Input",
  145. "test" => "Test",
  146. "exec" => "Ausführung",
  147. "value " => "Wert",
  148. "save" => "Sichern",
  149. "action" => "Aktion",
  150. "time" => "Zeit",
  151. "description" => "Beschreibung",
  152. "settings" => "Einstellungen",
  153. "babbles" => "Babble",
  154. "setparms" => "Parameter setzen",
  155. #--
  156. "hallo" => "Hallo",
  157. "state" => "Sicherheit",
  158. "unlocked" => "Unverschlossen",
  159. "locked" => "Verschlossen"
  160. );
  161. my $babble_tt;
  162. #########################################################################################
  163. #
  164. # Babble_Initialize
  165. #
  166. # Parameter hash = hash of device addressed
  167. #
  168. #########################################################################################
  169. sub Babble_Initialize ($) {
  170. my ($hash) = @_;
  171. $hash->{DefFn} = "Babble_Define";
  172. $hash->{SetFn} = "Babble_Set";
  173. $hash->{GetFn} = "Babble_Get";
  174. $hash->{UndefFn} = "Babble_Undef";
  175. #$hash->{AttrFn} = "Babble_Attr";
  176. my $attst = "lockstate:locked,unlocked helpFunc confirmFunc noChatBot:0,1 dnuFile testParm0 testParm1 testParm2 testParm3 ".
  177. "remoteFHEM0 remoteFHEM1 remoteFHEM2 remoteFHEM3 remoteFunc0 remoteFunc1 remoteFunc2 remoteFunc3 remoteToken0 remoteToken1 remoteToken2 remoteToken3 ".
  178. "babbleIds babblePreSubs babbleDevices babblePlaces babbleNotPlaces babbleVerbs babbleVerbParts babblePrepos babbleQuests babbleArticles babbleStatus babbleWrites babbleTimes";
  179. $hash->{AttrList} = $attst;
  180. if( !defined($babble_tt) ){
  181. #-- in any attribute redefinition readjust language
  182. my $lang = AttrVal("global","language","EN");
  183. if( $lang eq "DE"){
  184. $babble_tt = \%babble_transtable_DE;
  185. }else{
  186. $babble_tt = \%babble_transtable_EN;
  187. }
  188. }
  189. $babblelinkname = $babble_tt->{"babbles"};
  190. $data{FWEXT}{babblex}{LINK} = "?room=".$babblehiddenroom;
  191. $data{FWEXT}{babblex}{NAME} = $babblelinkname;
  192. #-- Create a new RiveScript interpreter
  193. Babble_createRive($hash)
  194. if( $rive==1 && !defined($hash->{Rive})) ;
  195. return undef;
  196. }
  197. #########################################################################################
  198. #
  199. # Babble_Define - Implements DefFn function
  200. #
  201. # Parameter hash = hash of device addressed, def = definition string
  202. #
  203. #########################################################################################
  204. sub Babble_Define ($$) {
  205. my ($hash, $def) = @_;
  206. my $now = time();
  207. my $name = $hash->{NAME};
  208. $hash->{VERSION} = $babbleversion;
  209. #-- readjust language
  210. my $lang = AttrVal("global","language","EN");
  211. if( $lang eq "DE"){
  212. $babble_tt = \%babble_transtable_DE;
  213. }else{
  214. $babble_tt = \%babble_transtable_EN;
  215. }
  216. readingsSingleUpdate( $hash, "state", "Initialized", 1 );
  217. $babblehiddenroom = defined($attr{$name}{"hiddenroom"}) ? $attr{$name}{"hiddenroom"} : $babblehiddenroom;
  218. $babblepublicroom = defined($attr{$name}{"publicroom"}) ? $attr{$name}{"publicroom"} : $babblepublicroom;
  219. $data{FWEXT}{babblex}{LINK} = "?room=".$babblehiddenroom;
  220. $data{FWEXT}{babblex}{NAME} = $babblelinkname;
  221. $attr{$name}{"room"} = $babblehiddenroom;;
  222. my $date = Babble_restore($hash,0);
  223. #-- data seems to be ok, restore
  224. if( defined($date) ){
  225. Babble_restore($hash,1);
  226. Log3 $name,1,"[Babble_Define] data hash restored from save file with date $date";
  227. #-- intialization
  228. }else{
  229. $hash->{DATA}{"devs"}=();
  230. $hash->{DATA}{"devcontacts"}=();
  231. $hash->{DATA}{"rooms"}=();
  232. $hash->{DATA}{"splaces"}=();
  233. $hash->{DATA}{"places"}=();
  234. $hash->{DATA}{"commands"}=();
  235. $hash->{DATA}{"help"}=();
  236. $hash->{DATA}{"status"}=();
  237. $hash->{DATA}{"writes"}=();
  238. $hash->{DATA}{"times"}=();
  239. Babble_checkattrs($hash);
  240. Log3 $name,1,"[Babble_Define] data hash is initialized";
  241. }
  242. #-- Create a new RiveScript interpreter
  243. Babble_createRive($hash)
  244. if( $rive==1 && !defined($hash->{Rive})) ;
  245. $modules{babble}{defptr}{$name} = $hash;
  246. RemoveInternalTimer($hash);
  247. InternalTimer ($now + 5, 'Babble_CreateEntry', $hash, 0);
  248. return;
  249. }
  250. #########################################################################################
  251. #
  252. # Babble_Undef - Implements Undef function
  253. #
  254. # Parameter hash = hash of device addressed, def = definition string
  255. #
  256. #########################################################################################
  257. sub Babble_Undef ($$) {
  258. my ($hash,$arg) = @_;
  259. my $name = $hash->{NAME};
  260. RemoveInternalTimer($hash);
  261. delete $data{FWEXT}{babblex};
  262. if (defined $defs{$name."_weblink"}) {
  263. FW_fC("delete ".$name."_weblink");
  264. Log3 $hash, 3, "[".$name. " V".$babbleversion."]"." Weblink ".$name."_weblink deleted";
  265. }
  266. return undef;
  267. }
  268. #########################################################################################
  269. #
  270. # Babble_Attr - Implements Attr function
  271. #
  272. # Parameter hash = hash of device addressed, ???
  273. #
  274. #########################################################################################
  275. sub Babble_Attr($$$) {
  276. my ($cmd, $name, $attrName, $attrVal) = @_;
  277. my $hash = $defs{"$name"};
  278. #-- in any attribute redefinition readjust language
  279. my $lang = AttrVal("global","language","EN");
  280. if( $lang eq "DE"){
  281. $babble_tt = \%babble_transtable_DE;
  282. }else{
  283. $babble_tt = \%babble_transtable_EN;
  284. }
  285. return;
  286. }
  287. #########################################################################################
  288. #
  289. # Babble_CreateEntry - Puts the babble entry into the FHEM menu
  290. #
  291. # Parameter hash = hash of device addressed
  292. #
  293. #########################################################################################
  294. sub Babble_CreateEntry($) {
  295. my ($hash) = @_;
  296. my $name = $hash->{NAME};
  297. if (!defined $defs{$name."_weblink"}) {
  298. FW_fC("define ".$name."_weblink weblink htmlCode {Babble_Html(\"".$name."\")}");
  299. Log3 $hash, 3, "[".$name. " V".$babbleversion."]"." Weblink ".$name."_weblink created";
  300. }
  301. FW_fC("attr ".$name."_weblink room ".$babblehiddenroom);
  302. foreach my $dn (sort keys %defs) {
  303. if ($defs{$dn}{TYPE} eq "FHEMWEB" && $defs{$dn}{NAME} !~ /FHEMWEB:/) {
  304. my $hr = AttrVal($defs{$dn}{NAME}, "hiddenroom", "");
  305. if (index($hr,$babblehiddenroom) == -1){
  306. if ($hr eq "") {
  307. FW_fC("attr ".$defs{$dn}{NAME}." hiddenroom ".$babblehiddenroom);
  308. }else {
  309. FW_fC("attr ".$defs{$dn}{NAME}." hiddenroom ".$hr.",".$babblehiddenroom);
  310. }
  311. Log3 $hash, 3, "[".$name. " V".$babbleversion."]"." Added hidden room '".$babblehiddenroom."' to ".$defs{$dn}{NAME};
  312. }
  313. }
  314. }
  315. #-- recover state from stored readings
  316. readingsBeginUpdate($hash);
  317. #readingsBulkUpdate( $hash, "state", $mga);
  318. readingsEndUpdate( $hash,1 );
  319. }
  320. #########################################################################################
  321. #
  322. # Babble_Set - Implements the Set function
  323. #
  324. # Parameter hash = hash of device addressed
  325. #
  326. #########################################################################################
  327. sub Babble_Set($@) {
  328. my ( $hash, $name, $cmd, @args ) = @_;
  329. if ( $cmd =~ /^lock(ed)?$/ ) {
  330. readingsSingleUpdate( $hash, "lockstate", "locked", 0 );
  331. return;
  332. #-----------------------------------------------------------
  333. } elsif ( $cmd =~ /^unlock(ed)?$/ ) {
  334. readingsSingleUpdate( $hash, "lockstate", "unlocked", 0 );
  335. return;
  336. #-----------------------------------------------------------
  337. } elsif ( $cmd =~ /^rivereload/ ) {
  338. delete $hash->{Rive};
  339. return Babble_createRive($hash);
  340. #-----------------------------------------------------------
  341. } elsif ( $cmd =~ /^test/ ) {
  342. return Babble_Test($hash);
  343. #-----------------------------------------------------------
  344. } elsif ( $cmd =~ /^save/ ) {
  345. return Babble_save($hash);
  346. #-----------------------------------------------------------
  347. } elsif ( $cmd =~ /^restore/ ) {
  348. return Babble_restore($hash,1);
  349. } else {
  350. my $str = "[babble] Unknown argument " . $cmd . ", choose one of locked:noArg unlocked:noArg save:noArg restore:noArg test:noArg ";
  351. $str .= "rivereload:noArg"
  352. if($rive == 1 && AttrVal($name,"noChatBot",0) != 1);
  353. return $str;
  354. }
  355. }
  356. #########################################################################################
  357. #
  358. # Babble_Get - Implements the Get function
  359. #
  360. # Parameter hash = hash of device addressed
  361. #
  362. #########################################################################################
  363. sub Babble_Get($@) {
  364. my ($hash, @a) = @_;
  365. my $res = "";
  366. my $ip;
  367. my $name = $hash->{NAME};
  368. my $arg = (defined($a[1]) ? $a[1] : "");
  369. if ($arg eq "version") {
  370. return "babble.version => $babbleversion";
  371. }elsif ($arg eq "tokens") {
  372. for( my $i=0;$i<=3;$i++ ){
  373. $ip = AttrVal($name,"remoteFHEM$i",undef);
  374. if( $ip ){
  375. Babble_getcsrf($name,$ip,$i);
  376. }
  377. }
  378. } else {
  379. return "Unknown argument $arg choose one of version:noArg tokens:noArg";
  380. }
  381. }
  382. #########################################################################################
  383. #
  384. # Babble_save
  385. #
  386. # Parameter hash = hash of the babble device
  387. #
  388. #########################################################################################
  389. sub Babble_save($) {
  390. my ($hash) = @_;
  391. my $date = TimeNow();
  392. my $name = $hash->{NAME};
  393. $hash->{DATA}{"savedate"} = $date;
  394. readingsSingleUpdate( $hash, "savedate", $date, 1 );
  395. my $jhash0 = toJSON($hash->{DATA});
  396. if( ReadingsVal($name,"lockstate","locked") ne "locked" ){
  397. my $error = FileWrite("babbleFILE",$jhash0);
  398. #Log3 $name, 1, " ".Dumper($jhash0);
  399. Log3 $name,1,"[Babble_save]";
  400. }else{
  401. Log3 $name, 1, "[Babble] attempt to save data failed due to lockstate";
  402. Log3 $name, 5, " ".Dumper($jhash0);
  403. }
  404. return;
  405. }
  406. sub Babble_savename($){
  407. my ($name) = @_;
  408. my $hash = $defs{$name};
  409. Babble_save($hash);
  410. }
  411. #########################################################################################
  412. #
  413. # Babble_restore
  414. #
  415. # Parameter hash = hash of the babble device
  416. #
  417. #########################################################################################
  418. sub Babble_restore($$) {
  419. my ($hash,$doit) = @_;
  420. my $name = $hash->{NAME};
  421. my ($error,@lines) = FileRead("babbleFILE");
  422. if( defined($error) && $error ne "" ){
  423. Log3 $name,1,"[Babble_restore] read error=$error";
  424. return undef;
  425. }
  426. my $json = JSON->new->utf8;
  427. my $jhash1 = eval{ $json->decode( join('',@lines) ) };
  428. my $date = $jhash1->{"savedate"};
  429. #-- just for the first time, reading an old savefile
  430. $date = localtime(time)
  431. if( !defined($date));
  432. readingsSingleUpdate( $hash, "savedate", $date, 0 );
  433. if( $doit==1 ){
  434. $hash->{DATA} = {%{$jhash1}};
  435. Log3 $name,1,"[Babble_restore] Data hash restored from save file with date ".$date;
  436. return 1;
  437. }else{
  438. return $date;
  439. }
  440. }
  441. #########################################################################################
  442. #
  443. # Babble_Test - Implements a variety of tests
  444. #
  445. # Parameter hash = hash of device addressed
  446. #
  447. #########################################################################################
  448. sub Babble_Test($) {
  449. my ($hash) = @_;
  450. my $name = $hash->{NAME};
  451. my $str = "";
  452. $str .= "\nA.1:".Babble_DoIt($name,"guten morgen","testit",0);
  453. $str .= "\nA.2:".Babble_DoIt($name,"gute nacht","testit",0);
  454. $str .= "\nA.3:".Babble_DoIt($name,"guten morgen jeannie","testit",0);
  455. $str .= "\nA.4:".Babble_DoIt($name,"gute nacht jeannie","testit",0);
  456. $str .= "\n";
  457. $str .= "\nB.1:".Babble_DoIt($name,"schalte das gerät an","testit",0);
  458. $str .= "\nB.2:".Babble_DoIt($name,"schalte gerät an","testit",0);
  459. $str .= "\nB.3:".Babble_DoIt($name,"mach das gerät an","testit",0);
  460. $str .= "\nB.4:".Babble_DoIt($name,"das gerät ausschalten","testit",0);
  461. $str .= "\nB.5:".Babble_DoIt($name,"gerät ausschalten","testit",0);
  462. $str .= "\nB.6:".Babble_DoIt($name,"das gerät ausmachen","testit",0);
  463. $str .= "\nB.7:".Babble_DoIt($name,"gerät anmachen","testit",0);
  464. $str .= "\nB.8:".Babble_DoIt($name,"schalte beleuchtung an","testit",0);
  465. $str .= "\nB.9:".Babble_DoIt($name,"licht anschalten","testit",0);
  466. $str .= "\n";
  467. $str .= "\nC.1:".Babble_DoIt($name,"wie ist der wert von gerät","testit",0);
  468. $str .= "\nC.2:".Babble_DoIt($name,"wie ist wert von gerät","testit",0);
  469. $str .= "\nC.3:".Babble_DoIt($name,"wie ist der wert gerät","testit",0);
  470. $str .= "\nC.4:".Babble_DoIt($name,"wie ist wert gerät","testit",0);
  471. $str .= "\nC.4:".Babble_DoIt($name,"sage den status von gerät","testit",0);
  472. $str .= "\nC.5:".Babble_DoIt($name,"sage status von gerät","testit",0);
  473. $str .= "\nC.6:".Babble_DoIt($name,"sage status gerät","testit",0);
  474. $str .= "\n";
  475. $str .= "\nD.1:".Babble_DoIt($name,"wie ist das wetter von morgen","testit",0);
  476. $str .= "\nD.2:".Babble_DoIt($name,"wie ist wetter von morgen","testit",0);
  477. $str .= "\nD.3:".Babble_DoIt($name,"wie ist das wetter morgen","testit",0);
  478. $str .= "\nD.4:".Babble_DoIt($name,"wie ist wetter morgen","testit",0);
  479. $str .= "\nD.5:".Babble_DoIt($name,"wie ist morgen das wetter","testit",0);
  480. $str .= "\nD.6:".Babble_DoIt($name,"wie ist morgen wetter","testit",0);
  481. $str .= "\nD.7:".Babble_DoIt($name,"wetter von morgen","testit",0);
  482. $str .= "\nD.8:".Babble_DoIt($name,"wetter morgen","testit",0);
  483. $str .= "\n";
  484. $str .= "\nF.1:".Babble_DoIt($name,"schalte den wecker aus","testit",0);
  485. $str .= "\nF.2:".Babble_DoIt($name,"schalte wecker aus","testit",0);
  486. $str .= "\nF.3:".Babble_DoIt($name,"den wecker ausschalten","testit",0);
  487. $str .= "\nF.4:".Babble_DoIt($name,"wecker ausschalten","testit",0);
  488. $str .= "\nF.5:".Babble_DoIt($name,"wie ist die weckzeit","testit",0);
  489. $str .= "\nF.6:".Babble_DoIt($name,"wie ist der status des weckers","testit",0);
  490. $str .= "\nF.7:".Babble_DoIt($name,"weckzeit ansagen","testit",0);
  491. $str .= "\nF.8:".Babble_DoIt($name,"weckzeit","testit",0);
  492. $str .= "\nF.9:".Babble_DoIt($name,"wecken um 4 uhr 3","testit",0);
  493. $str .= "\nF.10:".Babble_DoIt($name,"stelle den wecker auf 17:00","testit",0);
  494. $str .= "\nF.11:".Babble_DoIt($name,"wecken um 13:12 Uhr","testit",0);
  495. $str .= "\n";
  496. $str .= "\nG.1:".Babble_DoIt($name,"das haus ansagen","testit",0);
  497. $str .= "\nG.2:".Babble_DoIt($name,"haus ansagen","testit",0);
  498. $str .= "\nG.3:".Babble_DoIt($name,"haus status","testit",0);
  499. $str .= "\nG.4:".Babble_DoIt($name,"wie ist der status des hauses","testit",0);
  500. $str .= "\nG.5:".Babble_DoIt($name,"wie ist der status vom haus","testit",0);
  501. $str .= "\nG.6:".Babble_DoIt($name,"das haus sichern","testit",0);
  502. $str .= "\nG.7:".Babble_DoIt($name,"sichere das haus","testit",0);
  503. $str .= "\nG.8:".Babble_DoIt($name,"haus sichern","testit",0);
  504. $str .= "\nG.9:".Babble_DoIt($name,"das haus entsichern","testit",0);
  505. $str .= "\nG.10:".Babble_DoIt($name,"haus entsichern","testit",0);
  506. $str .= "\nG.11:".Babble_DoIt($name,"haustür öffnen","testit",0);
  507. $str .= "\nG.12:".Babble_DoIt($name,"die haustür öffnen","testit",0);
  508. $str .= "\nG.13:".Babble_DoIt($name,"öffne die haustür","testit",0);
  509. $str .= "\nG.14:".Babble_DoIt($name,"schließe die haustür zu","testit",0);
  510. $str .= "\nG.15:".Babble_DoIt($name,"schließe die haustür auf","testit",0);
  511. $str .= "\n";
  512. $str .= "\nH.1:".Babble_DoIt($name,"alarmanlage einschalten","testit",0);
  513. $str .= "\nH.1:".Babble_DoIt($name,"alarmanlage ein schalten","testit",0);
  514. $str .= "\nH.1:".Babble_DoIt($name,"die alarmanlage scharfschalten","testit",0);
  515. $str .= "\nH.2:".Babble_DoIt($name,"alarmanlage unscharf schalten","testit",0);
  516. $str .= "\nH.2:".Babble_DoIt($name,"die alarmanlage ausschalten","testit",0);
  517. $str .= "\nH.3:".Babble_DoIt($name,"schalte die alarmanlage scharf","testit",0);
  518. $str .= "\nH.4:".Babble_DoIt($name,"schalte den alarm an","testit",0);
  519. $str .= "\nH.5:".Babble_DoIt($name,"alarm wider rufen","testit",0);
  520. $str .= "\nH.6:".Babble_DoIt($name,"alarm widerrufen","testit",0);
  521. $str .= "\n";
  522. $str .= "\nI.1:".Babble_DoIt($name,"schalte beleuchtung in sitzgruppe an","testit",0);
  523. $str .= "\nI.2:".Babble_DoIt($name,"schalte beleuchtung in der sitzgruppe an","testit",0);
  524. $str .= "\nI.3:".Babble_DoIt($name,"mach die beleuchtung auf terrasse an","testit",0);
  525. $str .= "\nI.4:".Babble_DoIt($name,"mache außen die beleuchtung aus","testit",0);
  526. $str .= "\nI.5:".Babble_DoIt($name,"wie ist die temperatur im badezimmer","testit",0);
  527. $str .= "\nI.6:".Babble_DoIt($name,"wie ist die feuchte in dominics zimmer","testit",0);
  528. $str .= "\nI.7:".Babble_DoIt($name,"wie ist die feuchte in dem schlafzimmer","testit",0);
  529. $str .= "\nI.8:".Babble_DoIt($name,"wie ist der status der tür im schlafzimmer","testit",0);
  530. $str .= "\nI.9:".Babble_DoIt($name,"status tür schlafzimmer","testit",0);
  531. $str .= "\nI.10:".Babble_DoIt($name,"status der tür schlafzimmer","testit",0);
  532. $str .= "\nI.11:".Babble_DoIt($name,"status tür im schlafzimmer","testit",0);
  533. $str .= "\nI.12:".Babble_DoIt($name,"status der tür im schlafzimmer","testit",0);
  534. $str .= "\n";
  535. $str .= "\nJ.1:".Babble_DoIt($name,"stelle bei gerät den wert auf 8","testit",0);
  536. $str .= "\nJ.2:".Babble_DoIt($name,"stelle am gerät wert auf 9","testit",0);
  537. $str .= "\nJ.3:".Babble_DoIt($name,"stelle bei harmony den kanal auf 10","testit",0);
  538. $str .= "\nJ.4:".Babble_DoIt($name,"stelle am fernseher die lautstärke auf 11","testit",0);
  539. $str .= "\n";
  540. $str .= "\nK.1:".Babble_DoIt($name,"zur einkaufsliste hinzufügen bratheringe","testit",0);
  541. $str .= "\nK.2:".Babble_DoIt($name,"zu peters liste hinzufügen ticket münchen besorgen","testit",0);
  542. $str .= "\nK.3:".Babble_DoIt($name,"von dominics liste entfernen schmieröl","testit",0);
  543. $str .= "\nK.4:".Babble_DoIt($name,"baumarktliste löschen","testit",0);
  544. $str .= "\nK.5:".Babble_DoIt($name,"einkaufsliste senden","testit",0);
  545. return $str;
  546. }
  547. ##############################################################################
  548. #
  549. # Babble_Normalize
  550. #
  551. # Parameter hash = hash of the babble device
  552. #
  553. ##############################################################################
  554. sub Babble_Normalize($$){
  555. my ($name,$sentence) = @_;
  556. my $hash = $defs{$name};
  557. $sentence = lc $sentence;
  558. $sentence =~ s/[,.]//g;
  559. my $cat = 0;
  560. my $subcat = 0;
  561. my $subsubcat = 0;
  562. my ($device,$verb,$reading,$value,$article,$reserve,$place,$state,$prepo)=("","","","","","","","","","");
  563. #-- normalize special phrases
  564. my $sentmod = $sentence;
  565. my $pairs = AttrVal($name,"babblePreSubs",undef);
  566. if( $pairs ){
  567. my @subs=split(' ',$pairs);
  568. for( my $i=0; $i<int(@subs); $i++ ){
  569. my ($t,$r) = split( ':',$subs[$i],2 );
  570. $t =~ s/\\s/ /g;
  571. $r =~ s/\\s/ /g;
  572. $sentmod =~ s/$t/$r/;
  573. }
  574. }
  575. my @word = split(' ',$sentmod,15);
  576. my $len = int(@word);
  577. ############################# POS tagging ###################
  578. #-- isolate place - take out (prepo) [arti] PLACE
  579. # (verb) (prepo) [arti] PLACE [arti] (device)
  580. # (verb) [arti] (device) (prepo) [arti] PLACE
  581. # wie ist [arti] (device) (prepo) [arti] PLACE
  582. # wie ist (prepo) [arti] PLACE [arti] (device)
  583. $place = "none";
  584. for( my $i=0;$i<$len;$i++){
  585. if( $word[$i] =~ /^$hash->{DATA}{"re_places"}/ ){
  586. $place = $word[$i];
  587. my $to = 1;
  588. $to++
  589. if( ($i-1)>=0 && $word[$i-1] =~ /^$hash->{DATA}{"re_articles"}/ );
  590. $to++
  591. if( ($i-$to)>=0 && $word[$i-$to] =~ /^$hash->{DATA}{"re_prepos"}/ );
  592. for( my $j=$i+1-$to;$j<$len;$j++){
  593. $word[$j]=($word[$j+$to])?$word[$j+$to]:"";
  594. }
  595. last;
  596. }
  597. }
  598. #-- backup without place for reserve
  599. my @xord = @word;
  600. #-- leer
  601. if( int(@word) == 0){
  602. return ("","","","","","","");
  603. #-- Kategorie 1: Verb zuerst ----------------------------------------------------------
  604. # schalte das gerät an
  605. # schalte gerät an
  606. # sage den status von gerät
  607. # sage status von gerät
  608. # sage status gerät
  609. # schalte den wecker aus ;
  610. # schalte wecker aus
  611. }elsif( ($word[0] =~ /^$hash->{DATA}{"re_verbsc"}/) && ($word[1])){
  612. $cat = 1;
  613. #-- get infinitive
  614. $verb = $hash->{DATA}{"verbs"}{$word[0]};
  615. if( $word[1] =~ /^$hash->{DATA}{"re_articles"}/){
  616. $subcat = 1;
  617. $article = $word[1];
  618. $device = $word[2];
  619. $reading = $word[3];
  620. $reserve = $word[4];
  621. }elsif( $word[1] =~ /^$hash->{DATA}{"re_prepos"}/){
  622. $subcat = 2;
  623. $article = $word[1];
  624. $device = $word[2];
  625. }else{
  626. $subcat = 3;
  627. $device = $word[1];
  628. $reading = $word[2];
  629. $reserve = $word[3];
  630. }
  631. #-- device=state => verb="sage" => reading
  632. if( $hash->{DATA}{"re_status"} && $device =~ /^$hash->{DATA}{"re_status"}/ ){
  633. if( $reading =~ /^$hash->{DATA}{"re_prepos"}/ ){
  634. $subsubcat = 1;
  635. $reading = $device;
  636. $device = $reserve;
  637. }else{
  638. $subsubcat = 2;
  639. $reserve = $reading;
  640. $reading = $device;
  641. $device = $reserve;
  642. }
  643. #-- reading of device => target
  644. }elsif( $subcat==2 ){
  645. if( $word[3] =~ /^$hash->{DATA}{"re_articles"}/ ){
  646. $subsubcat = 3;
  647. $reading = $word[4];
  648. $reserve = $word[5];
  649. }else{
  650. $subsubcat = 4;
  651. $reading = $word[3];
  652. $reserve = $word[4];
  653. }
  654. }
  655. #-- Kategorie 2 ----------------------------------------------------------
  656. # wie ist der wert von gerät
  657. # wie ist wert von gerät
  658. # wie ist der wert gerät
  659. # wie ist wert gerät
  660. # wie ist das wetter morgen
  661. # wie ist wetter morgen
  662. # wie ist morgen das wetter
  663. # wie ist morgen wetter
  664. # wie ist die weckzeit
  665. # wie ist der status des weckers
  666. # (quest) ist (time) [arti1] (reading) [prepo] [arti2] ($device)
  667. }elsif( $word[0] =~ /^$hash->{DATA}{"re_quests"}/){
  668. $cat = 2;
  669. $verb = "sagen";
  670. my $inext;
  671. #-- check time
  672. if( $word[2] =~ /^$hash->{DATA}{"re_times"}/){
  673. $value = $word[2];
  674. $inext = 3;
  675. }else{
  676. $inext = 2;
  677. }
  678. #-- take out article
  679. if( $word[$inext] =~ /^$hash->{DATA}{"re_articles"}/){
  680. $subcat=1;
  681. $article = $word[$inext];
  682. $reading = $word[$inext+1];
  683. #-- check time => device is reading
  684. if( $word[$inext+2] =~ /^$hash->{DATA}{"re_times"}/){
  685. $subsubcat = 1;
  686. $value = $word[$inext+2];
  687. $device = $reading;
  688. #-- check time => device is reading
  689. }elsif( $word[$inext+2] =~ /^$hash->{DATA}{"re_prepos"}/ && $word[$inext+3] =~ /^$hash->{DATA}{"re_times"}/){
  690. $subsubcat = 2;
  691. $value = $word[$inext+3];
  692. $device = $reading;
  693. #--take out preposition
  694. }elsif( $word[$inext+2] =~ /^$hash->{DATA}{"re_prepos"}/ ){
  695. if( $word[$inext+3] =~ /^$hash->{DATA}{"re_articles"}/){
  696. $subsubcat = 3;
  697. $article = $word[$inext+3];
  698. $device = $word[$inext+4];
  699. }else{
  700. $subsubcat = 4;
  701. $device = $word[$inext+3];
  702. }
  703. #-- no preposition
  704. }else{
  705. if( $word[$inext+2] =~ /^$hash->{DATA}{"re_articles"}/){
  706. $subsubcat = 5;
  707. $article = $word[$inext+2];
  708. $device = $word[$inext+3];
  709. }else{
  710. $subsubcat = 6;
  711. $device = $word[$inext+2];
  712. }
  713. }
  714. #-- no article
  715. }else{
  716. $subcat=2;
  717. $reading = $word[$inext];
  718. #-- check time => device is reading
  719. if( $word[$inext+1] =~ /^$hash->{DATA}{"re_times"}/){
  720. $subsubcat = 1;
  721. $value = $word[$inext+1];
  722. $device = $reading;
  723. #-- check time => device is reading
  724. }elsif( $word[$inext+1] =~ /^$hash->{DATA}{"re_prepos"}/ && $word[$inext+2] =~ /^$hash->{DATA}{"re_times"}/){
  725. $subsubcat = 2;
  726. $value = $word[$inext+2];
  727. $device = $reading;
  728. #--take out preposition
  729. }elsif( $word[$inext+1] =~ /^$hash->{DATA}{"re_prepos"}/ ){
  730. if( $word[$inext+2] =~ /^$hash->{DATA}{"re_articles"}/){
  731. $subsubcat = 3;
  732. $article = $word[$inext+2];
  733. $device = $word[$inext+3];
  734. }else{
  735. $subsubcat = 4;
  736. $device = $word[$inext+2];
  737. }
  738. #-- no preposition
  739. }else{
  740. if( $word[$inext+1] =~ /^$hash->{DATA}{"re_articles"}/){
  741. $subsubcat = 5;
  742. $article = $word[$inext+1];
  743. $device = $word[$inext+2];
  744. }else{
  745. $subsubcat = 6;
  746. $device = $word[$inext+1];
  747. }
  748. }
  749. }
  750. if( $device eq ""){
  751. $subsubcat = 7;
  752. $device = $reading;
  753. $reading = "status";
  754. }
  755. #-- Kategorie 3 ----------------------------------------------------------
  756. # das gerät anschalten
  757. # gerät anschalten
  758. # das wetter von morgen
  759. # wetter von morgen
  760. # das wetter morgen
  761. # wetter morgen
  762. # guten morgen
  763. # gute nacht
  764. # den wecker ausschalten
  765. # wecker ausschalten
  766. # wecker
  767. # status
  768. }else{
  769. $cat = 3;
  770. my $rex = $hash->{DATA}{"re_verbparts"}." ?".$hash->{DATA}{"re_verbsi"};
  771. #-- guten morgen / gute nacht
  772. if( $word[0] =~ /^gut.*/){
  773. $subcat = 1;
  774. $device="zeit";
  775. $reading="status";
  776. $value=$word[1];
  777. $reserve=$word[2]
  778. if( $word[2] );
  779. $verb="schalten";
  780. #-- (arti) (device) something
  781. }elsif( $word[0] =~ /^$hash->{DATA}{"re_articles"}/){
  782. $subcat = 2;
  783. $article = $word[0];
  784. $device = $word[1];
  785. shift(@xord);
  786. shift(@xord);
  787. #--take out preposition
  788. if( $word[2] =~ /^$hash->{DATA}{"re_prepos"}/ ){
  789. $subsubcat = 1;
  790. shift(@xord);
  791. $reserve = join(" ",@xord);
  792. }else{
  793. $subsubcat = 2;
  794. $reserve = join(" ",@xord);
  795. }
  796. #-- (arti) (device) [prepo] (time)
  797. if( $reserve =~ /^$hash->{DATA}{"re_times"}/ ){
  798. $subsubcat = 3;
  799. #$reading = $reserve;
  800. $value = $reserve;
  801. $verb = "sagen";
  802. #-- (arti) (device) [prepo] verb
  803. }elsif( $reserve =~ s/^$hash->{DATA}{"re_verbsi"}\s?// ){
  804. $subsubcat = 4;
  805. $verb = $1;
  806. $reading = $reserve;
  807. #-- (arti) (device) [prepo] (reading) (verb) (value)
  808. }else{
  809. $subsubcat = 5;
  810. $reserve =~ /^$rex/;
  811. #-- named group
  812. $verb = $+{verbsi};
  813. $reading = $1;
  814. }
  815. #-- status [prepo] (device)
  816. }elsif( $word[0] =~ /^status/){
  817. $subcat = 3;
  818. #--take out preposition
  819. if( $word[1] =~ /^$hash->{DATA}{"re_prepos"}/ ){
  820. $subsubcat = 1;
  821. $device = $word[2];
  822. }else{
  823. $subsubcat = 2;
  824. $device = $word[1];
  825. }
  826. $verb = "sagen";
  827. $reading = "status";
  828. #-- (device) something
  829. }elsif($word[1] ne ""){
  830. $subcat = 4;
  831. $device = $word[0];
  832. shift(@xord);
  833. #--take out preposition
  834. if( $word[1] =~ /^$hash->{DATA}{"re_prepos"}/ ){
  835. $subsubcat = 1;
  836. shift(@xord);
  837. $reserve = join(" ",@xord);
  838. }else{
  839. $subsubcat = 2;
  840. $reserve = join(" ",@xord);
  841. }
  842. #-- (device) [prepo] (time)
  843. if( $reserve =~ /^$hash->{DATA}{"re_times"}/ ){
  844. $subsubcat = 3;
  845. $reading = "status";
  846. $value = $reserve;
  847. $verb = "sagen";
  848. #-- (device) [prepo] status
  849. }elsif( $reserve =~ /^status/ ){
  850. $subsubcat = 4;
  851. $reading = "status";
  852. $verb = "sagen";
  853. #-- (device) (write)
  854. }elsif( $word[1] =~ /^$hash->{DATA}{"re_writes"}/ ){
  855. $subsubcat = 5;
  856. $verb = $word[1];
  857. shift(@xord);
  858. $reading = join(" ",@xord);
  859. #-- (arti) (device) [prepo] verb
  860. }elsif( $reserve =~ s/^$hash->{DATA}{"re_verbsi"}\s?// ){
  861. $subsubcat = 6;
  862. $verb = $1;
  863. $reading = $reserve;
  864. #-- (device) [prepo] (reading) (verb) (value)
  865. }else{
  866. $subsubcat = 7;
  867. $reserve =~ /^$rex/;
  868. #-- named group
  869. $verb = $+{verbsi};
  870. $reading = $1;
  871. }
  872. #-- (device)
  873. }else{
  874. $subcat = 5;
  875. $device = $word[0];
  876. $reading = "status";
  877. $verb = "sagen";
  878. }
  879. }
  880. #-- normalize devices
  881. $device = "haus"
  882. if( $device =~/hauses/);
  883. $device = "wecker"
  884. if( $device =~/we((ck)|g).*/);
  885. $place = "wohnzimmer"
  886. if( ($device eq "licht") && ($place eq ""));
  887. if( $device eq "außenlicht" ){
  888. $place="aussen"
  889. if( $place eq "" );
  890. $device="licht";
  891. }
  892. #-- machen
  893. $verb = "schalten"
  894. if( $verb && $verb eq "machen");
  895. #-- sichern
  896. $reading = "zu"
  897. if(( $verb && $verb eq "sichern") && ($reading eq ""));
  898. #-- an
  899. $reading = "status"
  900. if( (( $verb && $verb eq "sagen") || ( $verb && $verb eq "zeigen")) && ($reading eq "an"));
  901. $reading = "an"
  902. if( $reading && $reading eq "ein");
  903. #-- value
  904. $value=substr($sentmod,index($sentmod,"auf")+4)
  905. if( ($reading && $reading eq "auf") || ($reserve && $reserve eq "auf") );
  906. $value=substr($sentmod,index($sentmod,"hinzufügen")+11)
  907. if( $reserve && $reserve =~ /hinzufügen (.*)/ );
  908. if( $verb && $verb eq "entfernen" ){
  909. $value = $reading;
  910. $reading = "ent";
  911. }
  912. if( $value =~ /.*uhr.*/ ){
  913. $value = Babble_timecorrector($value);
  914. }
  915. return ($device,$verb,$reading,$value,$article,$reserve,$place,"$cat.$subcat.$subsubcat");
  916. }
  917. #########################################################################################
  918. #
  919. # Babble_timecorrector - to correct for weird answers from Google
  920. #
  921. #########################################################################################
  922. sub Babble_timecorrector($){
  923. my ($value) = @_;
  924. my ($h,$m1,$m2);
  925. #-- xx:yy uhr und zz uhr
  926. if( $value =~/(\d?\d):(\d\d) uhr und (\d\d)( uhr)?/ ){
  927. $h = $1*1;
  928. $m1 = $2*1;
  929. $m2 = $3*1;
  930. return(sprintf("%2d\:%02d uhr",$h,$m1+$m2));
  931. #-- xx uhr zz uhr
  932. }elsif( $value =~/(\d?\d) uhr (\d\d)( uhr)?/ ){
  933. $h = $1*1;
  934. $m1 = $2*1;
  935. return(sprintf("%2d\:%02d uhr",$h,$m1));
  936. #-- xx:yy - no correction
  937. }elsif( $value =~/(\d?\d)(:(\d\d))?( uhr)?$/ ){
  938. $h = $1*1;
  939. $m1 = $3*1;
  940. if( $m1 eq "" ){
  941. $m1 = 0;
  942. }
  943. return(sprintf("%2d\:%02d uhr",$h,$m1));
  944. }else{
  945. return "xx";
  946. }
  947. }
  948. #########################################################################################
  949. #
  950. # Babble_createRive
  951. #
  952. #########################################################################################
  953. sub Babble_createRive($){
  954. my ($hash) = @_;
  955. my $name = $hash->{NAME};
  956. my $rs = $hash->{Rive};
  957. if( !defined($rs) ){
  958. $rs = new RiveScript(utf8=>1);
  959. $hash->{Rive} = $rs;
  960. Log3 $name, 1, "[Babble] new RiveScript interpreter generated";
  961. }
  962. #--load a directory of replies
  963. eval{$rs->loadDirectory ("./rivescript")};
  964. #-- sort all the loaded replies
  965. $rs->sortReplies;
  966. }
  967. #########################################################################################
  968. #
  969. # Babble_getcsrf
  970. #
  971. # Parameter ip = ip address of remote FHEM
  972. #
  973. #########################################################################################
  974. sub Babble_getcsrf($$$){
  975. my ($name,$ip,$i) = @_;
  976. my $url = "http://".$ip."/fhem";
  977. HttpUtils_NonblockingGet({
  978. url => $url,
  979. callback => sub($$$){
  980. my ($rhash,$err,$data) = @_;
  981. my $res = $rhash->{httpheader};
  982. $res =~ /X-FHEM-csrfToken\:\s(csrf_\d+).*/;
  983. CommandAttr(undef,$name." remoteToken$i ".$1);
  984. }
  985. });
  986. }
  987. ########################################################################################
  988. #
  989. # Babble_DoIt
  990. #
  991. # Parameter name = name of the babble definition
  992. #
  993. #########################################################################################
  994. sub Babble_DoIt{
  995. my ($name,$sentence,@parms) = @_;
  996. my $hash = $defs{$name};
  997. chomp ($sentence);
  998. my $testit = 0;
  999. my $exflag = 0;
  1000. my $confirm= 0;
  1001. my $res = "";
  1002. my $str = "";
  1003. my $star = "";
  1004. my $reply = "";
  1005. #-- semantic analysis
  1006. my ($device,$verb,$reading,$value,$article,$reserve,$place,$cat) = Babble_Normalize($name,$sentence);
  1007. $verb = "none"
  1008. if( !$verb );
  1009. $reading = "none"
  1010. if( !$reading );
  1011. if( @parms && $parms[0] eq "testit"){
  1012. $testit = 1;
  1013. shift @parms;
  1014. $exflag = $parms[0];
  1015. shift @parms;
  1016. for( my $i=0;$i<4;$i++){
  1017. $parms[$i] = AttrVal($name,"testParm".$i,undef)
  1018. if( !defined($parms[$i]) && AttrVal($name,"testParm".$i,undef));
  1019. }
  1020. $str="[Babble_Normalize] ".$babble_tt->{"input"}.": $sentence\n".
  1021. " ".$babble_tt->{"result"}.": Category=$cat: ".
  1022. $babble_tt->{"device"}."=$device ".$babble_tt->{"place"}."=$place ".
  1023. $babble_tt->{"verb"}."=$verb ".$babble_tt->{"target"}."=$reading / $value";
  1024. }
  1025. #-- find command directly
  1026. my $cmd = $hash->{DATA}{"command"}{$device}{$place}{$verb}{$reading};
  1027. #-- not directly - but maybe we have an alias device ?
  1028. if( !defined($cmd) || $cmd eq "" ){
  1029. my $alidev = $device;
  1030. $alidev =~s/_\d+$//g;
  1031. my $numalias = (defined($hash->{DATA}{"devsalias"}{$alidev})) ? int(@{$hash->{DATA}{"devsalias"}{$alidev}}) : 0;
  1032. for (my $i=0;$i<$numalias ;$i++){
  1033. my $ig = $hash->{DATA}{"devsalias"}{$alidev}[$i];
  1034. my $bdev = $hash->{DATA}{"devs"}[$ig];
  1035. my $lbdev = lc($bdev);
  1036. next
  1037. if( $lbdev eq $device );
  1038. $cmd = $hash->{DATA}{"command"}{$lbdev}{$place}{$verb}{$reading};
  1039. if( defined($cmd) && $cmd ne "" ){
  1040. $device = $lbdev;
  1041. last;
  1042. }
  1043. }
  1044. }
  1045. #-- not directly - but maybe we have a device which is an extension of an alias device
  1046. if( (!defined($cmd) || $cmd eq "") && defined($device) ){
  1047. my $realdev = $device;
  1048. foreach my $stardev (keys %{$hash->{DATA}{"devsalias"}}){
  1049. if(index($stardev,'*')!=-1){
  1050. my $starrexp = $stardev;
  1051. $starrexp =~ s/\*/\(\.\*\)/;
  1052. if( $realdev =~ /$starrexp/ ){
  1053. $star = $1;
  1054. $cmd = $hash->{DATA}{"command"}{$stardev}{$place}{$verb}{$reading};
  1055. if( defined($cmd) && $cmd ne "" ){
  1056. $device = $stardev;
  1057. last;
  1058. }
  1059. }
  1060. }
  1061. }
  1062. }
  1063. #-- command found after all
  1064. if( defined($cmd) && $cmd ne "" ){
  1065. #-- confirmation ?
  1066. if( index($cmd,"\$CONFIRM") != -1 ){
  1067. $confirm=1;
  1068. $cmd =~ s/;;\$CONFIRM$//;
  1069. }
  1070. #-- substitution
  1071. $cmd =~ s/\$DEV/$device/g;
  1072. $cmd =~ s/\$VALUE/$value/g;
  1073. for(my $i=0;$i<int(@parms);$i++){
  1074. $cmd =~ s/\$PARM$i/$parms[$i]/g;
  1075. }
  1076. if( $testit==0 || ($testit==1 && $exflag==1 )){
  1077. Log3 $name,1,"[Babble_DoIt] Executing from hash: $device.$place.$verb.$reading/$value ";
  1078. my $contact = $hash->{DATA}{"devcontacts"}{$device}[2];
  1079. my $fhemdev = $hash->{DATA}{"devcontacts"}{$device}[1];
  1080. if( $contact == 0 ){
  1081. $res = fhem($cmd);
  1082. }else{
  1083. my $ip = AttrVal($name,"remoteFHEM".$contact,undef);
  1084. my $token = AttrVal($name,"remoteToken".$contact,undef);
  1085. my $func = AttrVal($name,"remoteFunc".$contact,undef);
  1086. if( $func && $func ne "" ){
  1087. $res = eval($func."(\"".$cmd."\")")
  1088. }else{
  1089. $cmd =~ s/\s/\%20/g;
  1090. my $url = "http://".$ip."/fhem?XHR=1&amp;fwcsrf=".$token."&amp;cmd.$fhemdev=$cmd";
  1091. HttpUtils_NonblockingGet({
  1092. url => $url,
  1093. callback => sub($$$){}
  1094. });
  1095. }
  1096. }
  1097. #-- confirm execution
  1098. my $func = AttrVal($name,"confirmFunc",undef);
  1099. if( $confirm ){
  1100. if ($func && $func ne "" ){
  1101. #-- substitution
  1102. $func =~ s/\$DEV/$device/g;
  1103. $func =~ s/\$VALUE/$value/g;
  1104. for(my $i=0;$i<int(@parms);$i++){
  1105. $func =~ s/\$PARM$i/$parms[$i]/g;
  1106. }
  1107. $res = fhem($func);
  1108. }else{
  1109. Log3 $name,1,"[Babble_DoIt] Warning: requesting confirmation, but no attribute confirmFunc defined";
  1110. }
  1111. }
  1112. }
  1113. #-- what to do in conclusion
  1114. if( $testit==0 ){
  1115. return undef;
  1116. }else{
  1117. $str .= "==> $cmd";
  1118. return $str;
  1119. }
  1120. #-- no command found, acquire alternate text
  1121. }else{
  1122. #-- ChatBot available
  1123. if( $rive==1 && AttrVal($name,"noChatBot",0) != 1){
  1124. #-- Create a new RiveScript interpreter
  1125. Babble_createRive($hash)
  1126. if( !defined($hash->{Rive}) );
  1127. my $rs = $hash->{Rive};
  1128. $reply = $rs->reply ('localuser',$sentence);
  1129. if ($reply eq "ERR: No Reply Matched"){
  1130. $reply = $babble_tt->{dnu};
  1131. my $dnufile = AttrVal($name,"dnuFile",undef);
  1132. if( $dnufile ){
  1133. open(my $fh, '>>', $dnufile);
  1134. print $fh $sentence." => Category=$cat: ".
  1135. $babble_tt->{"device"}."=$device ".$babble_tt->{"place"}."=$place ".
  1136. $babble_tt->{"verb"}."=$verb ".$babble_tt->{"target"}."=$reading / $value\n";
  1137. close $fh;
  1138. }
  1139. }
  1140. #-- no chatbot, use help text directly
  1141. }else{
  1142. $reply = defined($hash->{DATA}{"help"}{$device}) ? $hash->{DATA}{"help"}{$device} : "";
  1143. }
  1144. #-- get help function
  1145. my $func = AttrVal($name,"helpFunc",undef);
  1146. if( $func && $func ne "" ){
  1147. #-- substitution
  1148. $func =~ s/\$HELP/$reply/g;
  1149. $func =~ s/\$DEV/$device/g;
  1150. $func =~ s/\$VALUE/$value/g;
  1151. for(my $i=0;$i<int(@parms);$i++){
  1152. $func =~ s/\$PARM$i/$parms[$i]/g;
  1153. }
  1154. if( $testit==0 ){
  1155. $res = eval($func);
  1156. return "";
  1157. }elsif($testit==1 && $exflag==1 ){
  1158. $res = eval($func);
  1159. return $str." ".$reply;
  1160. }else{
  1161. return $str." ".$func;
  1162. }
  1163. #-- no command, testing, no execution
  1164. }elsif( $testit==1 ){
  1165. Log 1,"[Babble_DoIt] Command $device.$place.$verb.$reading/$value undefined, reply = $reply";
  1166. $str = $reply;
  1167. }else{
  1168. $str = "";
  1169. }
  1170. return $str;
  1171. }
  1172. }
  1173. ########################################################################################
  1174. #
  1175. # Babble_checkattrs
  1176. #
  1177. # Parameter name = name of the babble definition
  1178. #
  1179. ########################################################################################
  1180. sub Babble_checkattrs($){
  1181. my ($hash) = @_;
  1182. my $name = $hash->{NAME};
  1183. CommandAttr (undef,$name." babbleVerbs schalt,schalte:schalten")
  1184. if( AttrVal($name,"babbleVerbs","") eq "" );
  1185. CommandAttr (undef,$name." babbleVerbParts zu auf ent wider ein an aus ab um")
  1186. if( AttrVal($name,"babbleVerbParts","") eq "" );
  1187. CommandAttr (undef,$name." babblePrepos von vom des der in im auf bei am")
  1188. if( AttrVal($name,"babblePrepos","") eq "" );
  1189. CommandAttr (undef,$name." babbleQuests wie wo wann")
  1190. if( AttrVal($name,"babbleQuests","") eq "" );
  1191. CommandAttr (undef,$name." babbleArticles der die das den des dem zur")
  1192. if( AttrVal($name,"babbleArticles","") eq "" );
  1193. CommandAttr (undef,$name." babbleStatus Status Wert Wetter Zeit")
  1194. if( AttrVal($name,"babbleStatus","") eq "" );
  1195. CommandAttr (undef,$name." babbleWrites setzen ändern löschen")
  1196. if( AttrVal($name,"babbleWrites","") eq "" );
  1197. CommandAttr (undef,$name." babbleTimes heute morgen übermorgen nacht")
  1198. if( AttrVal($name,"babbleTimes","") eq "" );
  1199. #}else{
  1200. # $hash->{DATA}{"verbsi"}[0]="switching";
  1201. # $hash->{DATA}{"verbsicc"}[0][0]="switch";
  1202. # CommandAttr (undef,$name." babbleVerbParts re un");
  1203. # CommandAttr (undef,$name." babbleQuests by of in on at");
  1204. # CommandAttr (undef,$name." babbleAdverb how where when");
  1205. # CommandAttr (undef,$name." babbleArticles the to");
  1206. # CommandAttr (undef,$name." babbleStatus status value weather time");
  1207. #}
  1208. }
  1209. #########################################################################################
  1210. #
  1211. # Babble_ModPlace
  1212. #
  1213. # Parameter name = name of the babble definition
  1214. #
  1215. #########################################################################################
  1216. sub Babble_ModPlace($$$){
  1217. my ($name,$place,$cmd) = @_;
  1218. my $hash = $defs{$name};
  1219. #-- remove a place (parameter is just a number)
  1220. if( $cmd == 0){
  1221. splice(@{$hash->{DATA}{"splaces"}},$place,1);
  1222. #-- add a place
  1223. }else{
  1224. push(@{$hash->{DATA}{"splaces"}},$place);
  1225. }
  1226. CommandAttr (undef,$name." babblePlaces ".join(" ",@{$hash->{DATA}{"splaces"}}));
  1227. Babble_getplaces($hash,"new",undef);
  1228. Babble_save($hash);
  1229. }
  1230. #########################################################################################
  1231. #
  1232. # Babble_ModVerb
  1233. #
  1234. # Parameter name = name of the babble definition
  1235. #
  1236. #########################################################################################
  1237. sub Babble_ModVerb($$$$){
  1238. my ($name,$verbi,$verbc,$cmd) = @_;
  1239. my $hash = $defs{$name};
  1240. my $verbi2 = $verbi;
  1241. my $verbc2 = $verbc;
  1242. # %{$hash->{DATA}{"verbs"}} = hash of all verb => infinitive_verb pairs
  1243. # @{$hash->{DATA}{"verbsi"}} = array of all infinite verbs
  1244. # @{$hash->{DATA}{"verbsicc"}} = array of all arrays of conjugated verbs
  1245. #-- remove a verb - verbi is only a number,verbc is empty
  1246. if( $cmd == 0){
  1247. $verbi2 = $hash->{DATA}{"verbsi"}[$verbi];
  1248. $verbc2 = join(',',$hash->{DATA}{"verbsicc"}[$verbi]);
  1249. splice(@{ $hash->{DATA}{"verbsi"}},$verbi,1);
  1250. splice(@{ $hash->{DATA}{"verbsicc"}},$verbi,1);
  1251. #-- add a verb
  1252. }elsif( $cmd==1) {
  1253. push(@{$hash->{DATA}{"verbsi"}},$verbi);
  1254. my @cc=split(',',$verbc);
  1255. push(@{$hash->{DATA}{"verbsicc"}},\@cc);
  1256. #-- modify a verb - verbi is only a number,verbc is a list of conjugations
  1257. }else{
  1258. $verbi2 = $hash->{DATA}{"verbsi"}[$verbi];
  1259. my @cc=split(',',$verbc);
  1260. $hash->{DATA}{"verbsicc"}[$verbi]=\@cc;
  1261. }
  1262. #-- recreate attribute
  1263. my $att = "";
  1264. for(my $i=0;$i<int(@{ $hash->{DATA}{"verbsi"}});$i++){
  1265. $att .= join(',',@{ $hash->{DATA}{"verbsicc"}[$i]}).":".$hash->{DATA}{"verbsi"}[$i]." ";
  1266. }
  1267. CommandAttr (undef,$name." babbleVerbs ".$att);
  1268. Babble_getverbs($hash,"new",undef);
  1269. Babble_save($hash);
  1270. }
  1271. ########################################################################################
  1272. #
  1273. # Babble_ModHlp
  1274. #
  1275. # Parameter name = name of the babble definition
  1276. #
  1277. #########################################################################################
  1278. sub Babble_ModHlp($$$){
  1279. my ($name,$bdev,$txt) = @_;
  1280. my $hash = $defs{$name};
  1281. #-- lower case characters
  1282. $bdev = lc($bdev);
  1283. $hash->{DATA}{"help"}{$bdev}=$txt;
  1284. }
  1285. ########################################################################################
  1286. #
  1287. # Babble_ModCmd
  1288. #
  1289. # Parameter name = name of the babble definition
  1290. #
  1291. #########################################################################################
  1292. sub Babble_ModCmd($$$$$$){
  1293. my ($name,$bdev,$place,$verb,$target,$cmd) = @_;
  1294. my $hash = $defs{$name};
  1295. #-- lower case characters
  1296. $bdev = lc($bdev);
  1297. if( defined($target) && $target ne "" ){
  1298. $target = lc($target);
  1299. delete($hash->{DATA}{"command"}{$bdev}{"none"}{"none"}{"none"})
  1300. }else{
  1301. $target="none"
  1302. };
  1303. if( defined($verb) && $verb ne "" ){
  1304. $verb = lc($verb);
  1305. delete($hash->{DATA}{"command"}{$bdev}{"none"}{"none"})
  1306. }else{
  1307. $verb="none"
  1308. };
  1309. if( defined($place) && $place ne "" ){
  1310. $place = lc($place);
  1311. delete($hash->{DATA}{"command"}{$bdev}{"none"})
  1312. }else{
  1313. $place="none"
  1314. };
  1315. #Log 1,"[Babble_ModCmd] Setting in hash: $bdev.$place.$verb.$target";
  1316. $hash->{DATA}{"command"}{$bdev}{$place}{$verb}{$target}=$cmd;
  1317. }
  1318. ########################################################################################
  1319. #
  1320. # Babble_RemCmd
  1321. #
  1322. # Parameter name = name of the babble definition
  1323. #
  1324. #########################################################################################
  1325. sub Babble_RemCmd($$$$$){
  1326. my ($name,$bdev,$place,$verb,$target) = @_;
  1327. my $hash = $defs{$name};
  1328. #-- lower case characters
  1329. $bdev = lc($bdev);
  1330. $place = lc($place);
  1331. $verb = lc($verb);
  1332. $target = lc($target);
  1333. $place="none"
  1334. if( $place eq "");
  1335. $verb="none"
  1336. if( $verb eq "");
  1337. $target="none"
  1338. if( $target eq "");
  1339. Log3 $name, 1,"[Babble_RemCmd] Deleting from hash: $bdev.$place.$verb.$target => ".$hash->{DATA}{"command"}{$bdev}{$place}{$verb}{$target};
  1340. delete($hash->{DATA}{"command"}{$bdev}{$place}{$verb}{$target});
  1341. }
  1342. #########################################################################################
  1343. #
  1344. # Babble_getids - Helper function to assemble id list
  1345. #
  1346. # Parameter hash = hash of device addressed
  1347. #
  1348. #########################################################################################
  1349. sub Babble_getids($$) {
  1350. my ($hash,$type) = @_;
  1351. my $name = $hash->{NAME};
  1352. my $res = "";
  1353. # @{$hash->{DATA}{"ids"}} = array of all ids
  1354. my @ids;
  1355. #--generate a new list
  1356. if( $type eq "new" ){
  1357. push(@ids,$babble_tt->{"hallo"});
  1358. #-- get ids from attribute
  1359. push(@ids,split(' ',AttrVal($name, "babbleIds", "")));
  1360. $hash->{DATA}{"re_ids"} = lc("((".join(")|(",@ids)."))");
  1361. return;
  1362. #-- just do something with the current list
  1363. }else{
  1364. return undef;
  1365. }
  1366. }
  1367. #########################################################################################
  1368. #
  1369. # Babble_getdevs - Helper function to assemble devices list
  1370. #
  1371. # Parameter hash = hash of device addressed
  1372. #
  1373. #########################################################################################
  1374. sub Babble_getdevs($$) {
  1375. my ($hash,$type) = @_;
  1376. my $name = $hash->{NAME};
  1377. # @{$hash->{DATA}{"devs"}} = array of all Babble devices
  1378. # %{$hash->{DATA}{"devcontacts"}} = hash of all arrays of contact data (Babble Device, FHEM Device, remote type)
  1379. my @remotes = (); # intermediate array of all remote groups of Babble device/FHEM device/contact data
  1380. my @devs = (); # intermediate array of all Babble devices with _number appendix
  1381. my %devshash = (); # intermediate hash of all Babble devices with _number appendix (for checking existence of name)
  1382. my %devsalias= (); # hash of arrays of all Babble device aliases without _number appendix
  1383. my @devcs = (); # intermediate array of all contact data for a certain device
  1384. my ($bdev,$lbdev,$sbdev,$fhemdev,$contact);
  1385. #--generate a new list
  1386. if( $type eq "new" ){
  1387. my $ig = 0;
  1388. $hash->{DATA}{"devs"}=();
  1389. $hash->{DATA}{"devcontacts"}=();
  1390. #-- local Babble devices raw data
  1391. foreach my $fhemdev (sort keys %defs ) {
  1392. $bdev = AttrVal($fhemdev, "babbleDevice",undef);
  1393. if( defined($bdev) ) {
  1394. Log3 $name,5,"[Babble_getdevs] finds local FHEM device $fhemdev with babbleDevice=$bdev";
  1395. $lbdev = lc($bdev);
  1396. $sbdev = $lbdev;
  1397. if(exists($devshash{$lbdev})) {
  1398. Log3 $name,1,"[Babble_getdevs] Warning: local FHEM device $fhemdev has duplicate babbleDevice=$bdev, is ignored. You need to specifiy ".$bdev."_<number> instead.";
  1399. }else{
  1400. Log3 $name,5,"[Babble_getdevs] local FHEM device $fhemdev with babbleDevice=$bdev entered into hashes with ig=$ig";
  1401. $devs[$ig] = $bdev;
  1402. #-- take away trailing _<num>
  1403. $sbdev =~ s/_\d+$//;
  1404. #-- put into hash
  1405. $hash->{DATA}{"devs"}[$ig] = $bdev;
  1406. $hash->{DATA}{"devcontacts"}{$lbdev}[0] = $bdev;
  1407. $hash->{DATA}{"devcontacts"}{$lbdev}[1] = $fhemdev;
  1408. $hash->{DATA}{"devcontacts"}{$lbdev}[2] = 0;
  1409. $devshash{$lbdev} = 1;
  1410. if( !defined($devsalias{$sbdev}) ){
  1411. $devsalias{$sbdev}[0]=$ig;
  1412. }else{
  1413. push(@{$devsalias{$sbdev}},$ig);
  1414. }
  1415. $ig++;
  1416. #-- safeguard against empty device
  1417. if( !defined($hash->{DATA}{"command"}{$lbdev})){
  1418. Log3 $name,1,"[Babble_getdevs] No entry in command table under $lbdev for local FHEM device $fhemdev with attribute babbleDevice=$bdev";
  1419. Babble_ModCmd($name,$sbdev,undef,undef,undef,undef)
  1420. }
  1421. }
  1422. }
  1423. }
  1424. #-- get devices from attribute
  1425. push(@remotes,split(' ',AttrVal($name, "babbleDevices", "")));
  1426. for (my $i=0;$i<int(@remotes);$i++){
  1427. ($bdev,$fhemdev,$contact) =split(':',$remotes[$i]);
  1428. $lbdev = lc($bdev);
  1429. $sbdev = $lbdev;
  1430. #-- take away trailing _<num>
  1431. $sbdev =~ s/_\d+$//;
  1432. if(exists($devshash{$lbdev})) {
  1433. Log3 $name,1,"[Babble_getdevs] Warning: remote FHEM device $fhemdev has duplicate babbleDevice=$bdev, is ignored. You need to specifiy ".$bdev."_<unique number> instead.";
  1434. }else{
  1435. Log3 $name,5,"[Babble_getdevs] remote FHEM device $fhemdev with babbleDevice=$bdev entered into hashes with ig=$ig";
  1436. $hash->{DATA}{"devs"}[$ig] = $bdev;
  1437. $hash->{DATA}{"devcontacts"}{$lbdev}[0] = $bdev;
  1438. $hash->{DATA}{"devcontacts"}{$lbdev}[1] = $fhemdev;
  1439. $hash->{DATA}{"devcontacts"}{$lbdev}[2] = $contact;
  1440. $devshash{$lbdev} = 1;
  1441. if( !defined($devsalias{$sbdev}) ){
  1442. $devsalias{$sbdev}[0]=$ig;
  1443. }else{
  1444. push(@{$devsalias{$sbdev}},$ig);
  1445. }
  1446. $ig++;
  1447. #-- safeguard against empty device
  1448. if( !defined($hash->{DATA}{"command"}{$lbdev})){
  1449. Log 1,"[Babble_getdevs] No entry in command table under $lbdev for remote FHEM device $fhemdev (remote $contact) with attribute babbleDevice=$bdev";
  1450. Babble_ModCmd($name,$sbdev,undef,undef,undef,undef)
  1451. }
  1452. }
  1453. }
  1454. #-- hash of devices without _<num>
  1455. %{$hash->{DATA}{"devsalias"}} = %devsalias;
  1456. #-- regex list for devices to check for validity
  1457. $hash->{DATA}{"re_devs"} = lc("((".join(")|(",@{$hash->{DATA}{"devs"}})."))")
  1458. if( defined($hash->{DATA}{"devs"}) );
  1459. #-- cleanup commands list for obsolete devices
  1460. if( defined( $hash->{DATA}{"command"} )){
  1461. foreach my $device (keys %{$hash->{DATA}{"command"}}){
  1462. if( !defined($hash->{DATA}{"devcontacts"}{$device}) ){
  1463. delete($hash->{DATA}{"command"}{$device});
  1464. }
  1465. }
  1466. }
  1467. }
  1468. }
  1469. #########################################################################################
  1470. #
  1471. # Babble_antistupidity - check for stupid naming of devices or rooms
  1472. # Parameter hash = hash of device addressed
  1473. #
  1474. #########################################################################################
  1475. sub Babble_antistupidity($) {
  1476. my ($hash) = @_;
  1477. my $name = $hash->{NAME};
  1478. my $regexp = $hash->{DATA}{"re_places"};
  1479. my $devs = $hash->{DATA}{"devs"};
  1480. return
  1481. if( !defined($regexp) || !defined($devs) );
  1482. my $imax = int(@{$hash->{DATA}{"devs"}});
  1483. for( my $i=0; $i<$imax; $i++){
  1484. my $dev = lc($hash->{DATA}{"devs"}[$i]);
  1485. Log 1,"[Babble] Baaaaah ! It is not a good idea to name a device $dev similar to a place in Babble"
  1486. if( $dev =~ /$regexp/ );
  1487. }
  1488. return undef;
  1489. }
  1490. #########################################################################################
  1491. #
  1492. # Babble_gethelp - Helper function
  1493. # Parameter hash = hash of device addressed
  1494. #
  1495. #########################################################################################
  1496. sub Babble_gethelp($$) {
  1497. my ($hash,$bdev) = @_;
  1498. my $name = $hash->{NAME};
  1499. my $lbdev = lc($bdev);
  1500. }
  1501. #########################################################################################
  1502. #
  1503. # Babble_getplaces - Helper function to assemble places list
  1504. #
  1505. # Parameter hash = hash of device addressed
  1506. #
  1507. #########################################################################################
  1508. sub Babble_getplaces($$$) {
  1509. my ($hash,$type,$sel) = @_;
  1510. my $name = $hash->{NAME};
  1511. # @{$hash->{DATA}{"rooms"}} = array of all rooms that are not hidden
  1512. # @{$hash->{DATA}{"splaces"}} = array of all special places for Babble
  1513. # @{$hash->{DATA}{"places"}} = array of all places for Babble = rooms + special
  1514. my %rooms; # intermediate hash of all rooms
  1515. my @special; # intermediate array of all special places for Babble
  1516. my @places; # intermediate array of rooms/all babble places
  1517. my $nop = AttrVal($name,"babbleNotPlaces","");
  1518. #--generate a new list
  1519. if( $type eq "new" ){
  1520. #-- code lifted from FHEMWEB
  1521. %rooms = (); # Make a room hash
  1522. my $hre = AttrVal($FW_wname, "hiddenroomRegexp", "");
  1523. foreach my $d (keys %defs ) {
  1524. #next if(IsIgnored($d));
  1525. foreach my $r (split(",", AttrVal($d, "room", "Unsorted"))) {
  1526. next if($hre && $r =~ m/$hre/);
  1527. next if($r eq "Unsorted" || $r eq "hidden" || $r eq $babblehiddenroom || $r eq $babblepublicroom );
  1528. next if (index($nop, $r) != -1);
  1529. $rooms{$r}{$d} = 1;
  1530. }
  1531. }
  1532. if(AttrVal($FW_wname, "sortRooms", "")) { # Slow!
  1533. my @sortBy = split( " ", AttrVal( $FW_wname, "sortRooms", "" ) );
  1534. my %sHash;
  1535. map { $sHash{$_} = FW_roomIdx(\@sortBy,$_) } keys %rooms;
  1536. @places = sort { $sHash{$a} cmp $sHash{$b} } keys %rooms;
  1537. } else {
  1538. @places = sort keys %rooms;
  1539. }
  1540. @{$hash->{DATA}{"rooms"}}=@places;
  1541. #-- append special places from attribute
  1542. @special = split(' ',AttrVal($name, "babblePlaces", ""));
  1543. @{$hash->{DATA}{"splaces"}} = @special;
  1544. push(@places, @special);
  1545. @{$hash->{DATA}{"places"}} = @places;
  1546. $hash->{DATA}{"re_places"} = lc("((".join(")|(",@places)."))");
  1547. #Babble_save($hash);
  1548. return;
  1549. #-- just do something with the current list
  1550. }elsif( $type eq "html" ){
  1551. @places=@{$hash->{DATA}{"places"}};
  1552. #-- output
  1553. if( !defined($sel) ){
  1554. return "<option></option><option>".join("</option><option>",@places)."</option>";
  1555. }else{
  1556. my $ret = ($sel eq "none") ? '<option selected="selected">' : '<option>';
  1557. $ret .= '</option>';
  1558. for( my $i=0;$i<int(@places);$i++){
  1559. $ret .= (lc($sel) eq lc($places[$i]) ) ? '<option selected="selected">' : '<option>';
  1560. $ret .= $places[$i].'</option>';
  1561. }
  1562. return $ret;
  1563. }
  1564. }else{
  1565. return undef;
  1566. }
  1567. }
  1568. #########################################################################################
  1569. #
  1570. # Babble_getverbs - Helper function to assemble verbs list
  1571. #
  1572. # Parameter hash = hash of device addressed
  1573. #
  1574. #########################################################################################
  1575. sub Babble_getverbs($$$) {
  1576. my ($hash,$type,$sel) = @_;
  1577. my $name = $hash->{NAME};
  1578. my $res = "";
  1579. # %{$hash->{DATA}{"verbs"}} = hash of all verb => infinitive_verb pairs
  1580. # @{$hash->{DATA}{"verbsi"}} = array of all infinite verbs
  1581. # @{$hash->{DATA}{"verbsicc"}} = array of all arrays of conjugated verbs
  1582. my @groups; # intermediate array of all conjugated_verb/infinitive_verb groups
  1583. my @verbsic; # intermediate array of all conjugations for a certain verb
  1584. #--generate a new list
  1585. if( $type eq "new" ){
  1586. #-- get verbs from attribute
  1587. push(@groups,split(' ',AttrVal($name, "babbleVerbs", "")));
  1588. for (my $i=0;$i<int(@groups);$i++){
  1589. my ($vc,$vi) =split(':',$groups[$i]);
  1590. $hash->{DATA}{"verbs"}{$vi} = $vi;
  1591. $hash->{DATA}{"verbsi"}[$i] = $vi;
  1592. @verbsic=split(',',$vc);
  1593. for (my $j=0;$j< int(@verbsic);$j++){
  1594. my $vcc = $verbsic[$j];
  1595. $hash->{DATA}{"verbs"}{$vcc} = $vi;
  1596. $hash->{DATA}{"verbsicc"}[$i][$j] = $vcc
  1597. }
  1598. }
  1599. $hash->{DATA}{"re_verbsi"} = "(?P<verbsi>(".lc( join(")|(",@{$hash->{DATA}{"verbsi"}}))."))";
  1600. $hash->{DATA}{"re_verbsc"} = lc("((".join(")|(",(keys %{$hash->{DATA}{"verbs"}}))."))");
  1601. return;
  1602. #-- just do something with the current list
  1603. }elsif( $type eq "html" ){
  1604. my @verbsi=@{$hash->{DATA}{"verbsi"}};
  1605. my $fnd = 0;
  1606. #-- output
  1607. if( !defined($sel) ){
  1608. return "<option></option><option>".join("</option><option>",@verbsi)."</option>";
  1609. }else{
  1610. my $ret = ($sel eq "none") ? '<option selected="selected">' : '<option>';
  1611. $ret .= '</option>';
  1612. for( my $i=0;$i<int(@verbsi);$i++){
  1613. if( lc($sel) eq lc($verbsi[$i]) ) {
  1614. $ret .= '<option selected="selected">';
  1615. $fnd = 1;
  1616. }else{
  1617. $ret .= '<option>';
  1618. }
  1619. $ret .= $verbsi[$i].'</option>';
  1620. }
  1621. #if( $fnd==0 ){
  1622. # $ret .= '<option selected="selected" value="unknown">'.$babble_tt->{"unknown"}.'</option>';
  1623. #}
  1624. return $ret;
  1625. }
  1626. }else{
  1627. return undef;
  1628. }
  1629. }
  1630. #########################################################################################
  1631. #
  1632. # Babble_getwords - Helper function to assemble list of other word classes
  1633. #
  1634. # Parameter hash = hash of device addressed
  1635. #
  1636. #########################################################################################
  1637. sub Babble_getwords($$$$) {
  1638. my ($hash,$class,$type,$sel) = @_;
  1639. my $name = $hash->{NAME};
  1640. my $res = "";
  1641. my @words;
  1642. if( $type eq "new" ){
  1643. if( $class eq "verbparts" || $class eq "all" ) {
  1644. @words=split(' ',AttrVal($name, "babbleVerbParts", ""));
  1645. @{$hash->{DATA}{"verbparts"}} = @words;
  1646. $hash->{DATA}{"re_verbparts"} = lc("((".join(")|(",@words)."))");
  1647. }
  1648. if( $class eq "prepos" || $class eq "all" ) {
  1649. @words=split(' ',AttrVal($name, "babblePrepos", ""));
  1650. @{$hash->{DATA}{"prepos"}} = @words;
  1651. $hash->{DATA}{"re_prepos"} = lc("((".join(")|(",@words)."))");
  1652. }
  1653. if( $class eq "articles" || $class eq "all" ) {
  1654. @words=split(' ',AttrVal($name, "babbleArticles", ""));
  1655. @{$hash->{DATA}{"articles"}} = @words;
  1656. $hash->{DATA}{"re_articles"} = lc("((".join(")|(",@words)."))");
  1657. }
  1658. if( $class eq "status" || $class eq "all" ) {
  1659. @words=split(' ',AttrVal($name, "babbleStatus", ""));
  1660. @{$hash->{DATA}{"status"}} = @words;
  1661. $hash->{DATA}{"re_status"} = lc("((".join(")|(",@words)."))");
  1662. }
  1663. if( $class eq "times" || $class eq "all" ) {
  1664. @words=split(' ',AttrVal($name, "babbleTimes", ""));
  1665. @{$hash->{DATA}{"times"}} = @words;
  1666. $hash->{DATA}{"re_times"} = lc("((".join(")|(",@words)."))");
  1667. }
  1668. if( $class eq "quests" || $class eq "all" ) {
  1669. @words=split(' ',AttrVal($name, "babbleQuests", ""));
  1670. @{$hash->{DATA}{"quests"}} = @words;
  1671. $hash->{DATA}{"re_quests"} = lc("((".join(")|(",@words)."))");
  1672. }
  1673. if( $class eq "writes" || $class eq "all" ) {
  1674. @words=split(' ',AttrVal($name, "babbleStatus", ""));
  1675. @{$hash->{DATA}{"writes"}} = @words;
  1676. $hash->{DATA}{"re_writes"} = lc("((".join(")|(",@words)."))");
  1677. }
  1678. delete($hash->{DATA}{"pronouns"});
  1679. #Babble_save($hash);
  1680. return;
  1681. #-- just do something with the current list
  1682. }elsif( $class eq "targets" && $type eq "html" ){
  1683. my @targets=@{$hash->{DATA}{"status"}};
  1684. push(@targets,"----");
  1685. push(@targets,@{$hash->{DATA}{"verbparts"}});
  1686. #-- output
  1687. if( !defined($sel) ){
  1688. return "<option></option><option>".join("</option><option>",@targets)."</option>";
  1689. }else{
  1690. my $ret = ($sel eq "none") ? '<option selected="selected">' : '<option>';
  1691. $ret .= '</option>';
  1692. for( my $i=0;$i<int(@targets);$i++){
  1693. $ret .= (lc($sel) eq lc($targets[$i]) ) ? '<option selected="selected">' : '<option>';
  1694. $ret .= $targets[$i].'</option>';
  1695. }
  1696. return $ret;
  1697. }
  1698. }else{
  1699. return undef;
  1700. }
  1701. }
  1702. #########################################################################################
  1703. #
  1704. # Babble_Html - returns HTML code for the babble page
  1705. #
  1706. # Parameter name = name of the babble definition
  1707. #
  1708. #########################################################################################
  1709. sub Babble_Html($)
  1710. {
  1711. my ($name) = @_;
  1712. my $ret = "";
  1713. my $rot = "";
  1714. my $hash = $defs{$name};
  1715. my $id = $defs{$name}{NR};
  1716. if( !defined($babble_tt) ){
  1717. #-- readjust language
  1718. my $lang = AttrVal("global","language","EN");
  1719. if( $lang eq "DE"){
  1720. $babble_tt = \%babble_transtable_DE;
  1721. }else{
  1722. $babble_tt = \%babble_transtable_EN;
  1723. }
  1724. }
  1725. Babble_checkattrs($hash);
  1726. Babble_getids($hash,"new");
  1727. Babble_getdevs($hash,"new");
  1728. my $pllist = Babble_getplaces($hash,"new",undef);
  1729. Babble_antistupidity($hash);
  1730. my $pmlist="";
  1731. for(my $i=0;$i<int(@{$hash->{DATA}{"splaces"}});$i++){
  1732. $pmlist .= "<a onclick=\"babble_modplace('$name','".$hash->{DATA}{"splaces"}[$i]."',$i)\">".$hash->{DATA}{"splaces"}[$i]."</a> ";
  1733. }
  1734. my $vblist = Babble_getverbs($hash,"new",undef);
  1735. my $vmlist="";
  1736. for(my $i=0;$i<int(@{$hash->{DATA}{"verbsi"}});$i++){
  1737. my $vi = $hash->{DATA}{"verbsi"}[$i];
  1738. my $vmilist = join(',',@{$hash->{DATA}{"verbsicc"}[$i]});
  1739. $vmlist .= "<a onclick=\"babble_modverb('$name','".$vi."','".$vmilist."',$i)\">".$vi."</a> ";
  1740. }
  1741. my $vpmlist = Babble_getwords($hash,"all","new",undef);
  1742. #-- update state display
  1743. #readingsSingleUpdate( $hash, "state", Babble_getstate($hash)." ".$hash->{READINGS}{"short"}{VAL}, 1 );
  1744. #--
  1745. my $lockstate = ($hash->{READINGS}{lockstate}{VAL}) ? $hash->{READINGS}{lockstate}{VAL} : "unlocked";
  1746. my $showhelper = ($lockstate eq "unlocked") ? 1 : 0;
  1747. #--
  1748. $ret .= "<script type=\"text/javascript\" src=\"$FW_ME/pgm2/babble.js\"></script><script type=\"text/javascript\">\n";
  1749. $ret .= "var tt_add='".$babble_tt->{"add"}."';\n";
  1750. $ret .= "var tt_added='".$babble_tt->{"added"}."';\n";
  1751. $ret .= "var tt_remove='".$babble_tt->{"remove"}."';\n";
  1752. $ret .= "var tt_removed='".$babble_tt->{"removed"}."';\n";
  1753. $ret .= "var tt_modify='".$babble_tt->{"modify"}."';\n";
  1754. $ret .= "var tt_modified='".$babble_tt->{"modified"}."';\n";
  1755. $ret .= "var tt_cancel='".$babble_tt->{"cancel"}."';\n";
  1756. $ret .= "var tt_place='".$babble_tt->{"place"}."';\n";
  1757. $ret .= "var tt_verb='".$babble_tt->{"verb"}."';\n";
  1758. $ret .= "var newplace = '<select name=\"d_place\">".Babble_getplaces($hash,"html","none")."</select>';\n";
  1759. $ret .= "var newverbs = '<select name=\"d_verb\">".Babble_getverbs($hash, "html","none")."</select>';\n";
  1760. $ret .= "var newtargs = '<select name=\"d_verbpart\">".Babble_getwords($hash,"targets","html","none")."</select>';\n";
  1761. $ret .= "var newfield = '<input type=\"text\" name=\"d_command\" size=\"30\" maxlength=\"512\" value=\"FHEM command\">';\n";
  1762. $ret .= "var newcheck = '<input type=\"checkbox\" name=\"d_confirm\">';\n";
  1763. $rot .= "</script>\n";
  1764. $rot .= "<table class=\"roomoverview\">\n";
  1765. #-- test table
  1766. $rot .= "<tr><td colspan=\"3\"><div class=\"devType\">".$babble_tt->{"babbletest"}."</div></td></tr>";
  1767. $rot .= "<tr><td colspan=\"3\"><table class=\"block wide\" id=\"testtable\">\n";
  1768. $rot .= "<tr class=\"odd\" ><td class=\"col1\">".$babble_tt->{"input"}.": <input type=\"text\" id=\"d_testcommand\" size=\"60\" maxlength=\"512\"/></td>\n".
  1769. "<td class=\"col1\" style=\"text-align:left\"><input type=\"button\" id=\"b_testit\" onclick=\"babble_testit('".$name."')\" value=\"".$babble_tt->{"test"}."\" style=\"width:100px;\"/</td></tr>\n".
  1770. "<tr class=\"even\"><td class=\"col1\">".$babble_tt->{"result"}.": <div id=\"d_testresult\"></div></td>\n".
  1771. "<td class=\"col1\" style=\"text-align:left\"><input type=\"checkbox\" id=\"b_execit\">".$babble_tt->{"exec"}."</td></tr>\n";
  1772. $rot .= "</table></td></tr>";
  1773. #-- places table
  1774. my $tblrow=1;
  1775. $rot .= "<tr><td colspan=\"3\"><div class=\"devType\">".$babble_tt->{"babbleplaces"}."</div></td></tr>";
  1776. $rot .= "<tr><td colspan=\"3\"><table class=\"block wide\" id=\"placestable\">\n";
  1777. $rot .= "<tr class=\"odd\"><td class=\"col1\">".$babble_tt->{"rooms"}."</td><td class=\"col1\" colspan=\"2\" style=\"horizontal-align:left\">".join(" ",@{$hash->{DATA}{"rooms"}})."</td></tr>\n".
  1778. "<tr class=\"even\"><td class=\"col1\">".$babble_tt->{"places"}."</td><td class=\"col1\" colspan=\"2\" style=\"align:left\">".$pmlist."</td></tr>\n".
  1779. "<tr class=\"odd\"><td class=\"col1\"><input type=\"button\" id=\"b_addplace\" onclick=\"babble_addplace('".$name."')\" value=\"".$babble_tt->{"add"}."\" style=\"width:100px;\"/>".
  1780. "<div id=\"b_chgplacediv\" style=\"width:100px\"></div></td>".
  1781. "<td class=\"col3\" colspan=\"2\"><input type=\"text\" id=\"b_newplace\" size=\"40\" maxlength=\"120\" ></td></tr>\n";
  1782. $rot .= "</table></td></tr>";
  1783. #-- verbs table
  1784. $tblrow=1;
  1785. $rot .= "<tr><td colspan=\"3\"><div class=\"devType\">".$babble_tt->{"babbleverbs"}."</div></td></tr>";
  1786. $rot .= "<tr><td colspan=\"3\"><table class=\"block wide\" id=\"verbstable\">\n";
  1787. $rot .= "<tr class=\"odd\"><td class=\"col1\">".$babble_tt->{"verbs"}."</td><td class=\"col1\" colspan=\"2\" style=\"align:left\">".$vmlist."</td></tr>\n".
  1788. "<tr class=\"even\"><td class=\"col1\"></td>".
  1789. "<td class=\"col3\">".$babble_tt->{"conjugations"}."</td><td class=\"col3\">".$babble_tt->{"infinitive"}."</td></tr>\n".
  1790. "<tr class=\"odd\"><td class=\"col1\"><input type=\"button\" id=\"b_addverb\" onclick=\"babble_addverb('".$name."')\" value=\"".$babble_tt->{"add"}.
  1791. "\" style=\"width:100px;\"/><div id=\"b_chgverbdiv\" style=\"width:100px\"></div></td>".
  1792. "<td class=\"col3\"><input type=\"text\" id=\"b_newverbc\" size=\"20\" maxlength=\"120\" ></td><td class=\"col3\"><input type=\"text\" id=\"b_newverbi\" size=\"20\" maxlength=\"120\" ></td></tr>\n";
  1793. $rot .= "</table></td></tr>";
  1794. #-- devices table
  1795. $tblrow = 0;
  1796. my $ig = 0;
  1797. my $devcount = 0;
  1798. my @devrows = ();
  1799. my($devrow,$ip,$ipp);
  1800. $rot .= "<tr><td colspan=\"3\"><div class=\"devType\">".$babble_tt->{"babbledev"}."</div></td></tr>";
  1801. $rot .= "<tr><td colspan=\"3\"><table class=\"block wide\" id=\"devstable\">\n";
  1802. $rot .= "<tr class=\"odd\"><td class=\"col1\" style=\"text-align:left;padding-right:10px;\">".$babble_tt->{"fhemname"}."</td><td class=\"col2\" style=\"text-align:left\">".$babble_tt->{"device"}."</td>\n".
  1803. "<td class=\"col3\">".$babble_tt->{"place"}."</td><td class=\"col3\">".$babble_tt->{"verb"}."</td><td class=\"col3\">".$babble_tt->{"target"}."</td>\n".
  1804. "<td class=\"col3\">".$babble_tt->{"action"}."</td><td class=\"col3\">".$babble_tt->{"confirm"}."</td><td class=\"col3\"><input type=\"button\" id=\"d_save\" onclick=\"babble_savedevs('".$name."')\" value=\"".$babble_tt->{"save"}.
  1805. "\" style=\"width:100px;\"/></td></tr>\n";
  1806. #-- loop over all unique devices to get some sorting
  1807. if( defined($hash->{DATA}{"devsalias"}) ){
  1808. for my $alidev (sort keys %{$hash->{DATA}{"devsalias"}}) {
  1809. #-- number of devices with this unique
  1810. my $numalias = int(@{$hash->{DATA}{"devsalias"}{$alidev}});
  1811. for (my $i=0;$i<$numalias ;$i++){
  1812. $ig = $hash->{DATA}{"devsalias"}{$alidev}[$i];
  1813. my $bdev = $hash->{DATA}{"devs"}[$ig];
  1814. my $lbdev = lc($bdev);
  1815. my $sbdev = $bdev;
  1816. $sbdev =~s/_\d+$//g;
  1817. my $lsbdev = $lbdev;
  1818. $lsbdev =~s/_\d+$//g;
  1819. my $hlp = $hash->{DATA}{"help"}{$lbdev};
  1820. if( !defined($hlp) ){
  1821. $hlp = $babble_tt->{"speak"}.": ".$sbdev.", ".$babble_tt->{"followedby"}." ";
  1822. #-- places ?
  1823. if( join('_',(keys %{$hash->{DATA}{"command"}{$lbdev}})) ne "none"){;
  1824. $hlp .= $babble_tt->{"placespec"}.", ".$babble_tt->{"followedby"}." ";
  1825. }
  1826. }
  1827. my $checked;
  1828. my $fhemdev = $hash->{DATA}{"devcontacts"}{$lbdev}[1];
  1829. my $contact = $hash->{DATA}{"devcontacts"}{$lbdev}[2];
  1830. $devcount++;
  1831. $tblrow++;
  1832. $ig++;
  1833. $devrow=1;
  1834. #-- headline for device
  1835. $rot .= sprintf("<tr class=\"%s\" style=\"padding-right:25px;\">", ($tblrow&1)?"odd":"even");
  1836. $rot .= "<td width=\"240\" class=\"col1\" style=\"text-align:left;padding-right:10px; border-top:1px solid gray\">";
  1837. #-- local link to device
  1838. if( $contact == 0 ){
  1839. $rot .= "<a href=\"$FW_ME?detail=$fhemdev\">$fhemdev</a>";
  1840. #-- remote link to device
  1841. }else{
  1842. $ip = AttrVal($name,"remoteFHEM".$contact,undef);
  1843. $ipp = $ip =~ s/:.*//sr;
  1844. if( $ip ){
  1845. $rot .= "<a href=\"http://".$ip."/fhem?detail=$fhemdev\">$fhemdev</a> ($ipp)";
  1846. }else{
  1847. $rot .= $fhemdev." (R$contact)";
  1848. }
  1849. }
  1850. $rot .= "</td>\n<td class=\"col2\" style=\"text-align:left; border-top:1px solid gray;padding:2px\">$bdev</td>\n";
  1851. $rot .= "</td>\n<td class=\"col2\" style=\"text-align:right; border-left:1px dotted gray; border-bottom: 1px dotted gray;border-top:1px solid gray;border-bottom-left-radius:10px; padding:2px\">".$babble_tt->{"helptext"}."&rarr;</td>";
  1852. #-- helptext
  1853. $rot .= "<td class=\"col3\" colspan=\"4\" style=\"text-align:left;border-right:1px dotted gray;border-bottom: 1px dotted gray;border-top:1px solid gray;border-bottom-right-radius:10px; padding:2px;\">";
  1854. $rot .= "<input type=\"text\" name=\"d_help\" size=\"51\" maxlength=\"1024\" value=\"".$hlp."\"/></td>";
  1855. $rot .= "<td style=\"text-align:left;padding-right:10px; border-top:1px solid gray\">".
  1856. "<input type=\"button\" id=\"d_addrow\" onclick=\"babble_addrow('".$name."',$devcount,$tblrow)\" value=\"".$babble_tt->{"add"}."\" style=\"width:100px;\"/></td></tr>\n";#$tblrow-$devcount.$devrow
  1857. #my $json = JSON->new->utf8;
  1858. #my $jhash0 = eval{ $json->encode( $hash->{DATA}{"command"}{$lbdev} ) };
  1859. #Log3 $name, 1, "\n\n\n\n $lbdev ========>".Dumper($jhash0);
  1860. foreach my $place (keys %{$hash->{DATA}{"command"}{$lbdev}}){
  1861. foreach my $verb (keys %{$hash->{DATA}{"command"}{$lbdev}{$place}}){
  1862. foreach my $target (keys %{$hash->{DATA}{"command"}{$lbdev}{$place}{$verb}}){
  1863. my $cmd = $hash->{DATA}{"command"}{$lbdev}{$place}{$verb}{$target};
  1864. if( index($cmd,"\$CONFIRM") != -1 ){
  1865. $checked = "checked=\"checked\" ";
  1866. $cmd =~ s/;;\$CONFIRM$//;
  1867. }else{
  1868. $checked="";
  1869. }
  1870. $tblrow++;
  1871. $devrow++;
  1872. $rot .= sprintf("<tr class=\"%s\" style=\"padding-right:25px;\"><td></td><td></td>\n", ($tblrow&1)?"odd":"even");
  1873. $pllist = Babble_getplaces($hash,"html",$place);
  1874. $vblist = Babble_getverbs($hash, "html",$verb);
  1875. $vpmlist = Babble_getwords($hash,"targets","html",$target);
  1876. $rot .= "<td class=\"col3\"><select name=\"d_place\">".$pllist."</select></td>".
  1877. "<td class=\"col3\"><select name=\"d_verb\">".$vblist."</select></td>".
  1878. "<td class=\"col3\"><select name=\"d_verbpart\">".$vpmlist."</select></td>\n";
  1879. $rot .= "<td class=\"col3\" style=\"text-align:left;padding:2px\"><input type=\"text\" name=\"d_command\" size=\"30\" maxlength=\"512\" value=\"".$cmd."\"/></td>";
  1880. $rot .= "<td class=\"col3\"><input type=\"checkbox\" name=\"d_confirm\"$checked</td>";
  1881. $rot .= "<td><input type=\"button\" id=\"d_remrow\" onclick=\"babble_remrow('".$name."',$devcount,$tblrow)\" value=\"".$babble_tt->{"remove"}."\" style=\"width:100px;\"/></td></tr>\n";#$tblrow-$devcount.$devrow
  1882. }
  1883. }
  1884. }
  1885. push(@devrows,$devrow)
  1886. }
  1887. }
  1888. $rot .= "</table></td></tr>";
  1889. }
  1890. $rot .= "</table>";
  1891. $ret .= "var devrows=[".( (@devrows) ? join(",",@devrows) : "")."];\n";
  1892. $ret .= "var devrowstart=devrows;\n";
  1893. return $ret.$rot;
  1894. }
  1895. 1;
  1896. =pod
  1897. =item helper
  1898. =item summary for speech control of FHEM devices
  1899. =begin html
  1900. <a name="Babble"></a>
  1901. <h3>Babble</h3>
  1902. <ul>
  1903. <p> FHEM module for speech control of FHEM devices</p>
  1904. <a name="babbleusage"></a>
  1905. <h4>Usage</h4>
  1906. See <a href="http://www.fhemwiki.de/wiki/Modul_babble">German Wiki page</a>
  1907. <a name="babbledefine"></a>
  1908. <br/>
  1909. <h4>Define</h4>
  1910. <p>
  1911. <code>define &lt;name&gt; babble</code>
  1912. <br />Defines the Babble device. </p>
  1913. <a name="babbleset"></a>
  1914. Notes: <ul>
  1915. <li>This module uses the global attribute <code>language</code> to determine its output data<br/>
  1916. (default: EN=english). For German output set <code>attr global language DE</code>.</li>
  1917. <li>This module needs the JSON package.</li>
  1918. <li>Only when the chatbot functionality of RiveScript is required, the RiveScript module must be installed as well, see https://github.com/aichaos/rivescript-perl</li>
  1919. </ul>
  1920. <h4>Usage</h4>
  1921. To use this module, call the Perl function <code>Babble_DoIt("&lt;name&gt;","&lt;sentence&gt;"[,&lt;parm0&gt;,&lt;parm1&gt;,...])</code>.
  1922. &lt;name&gt; is the name of the Babble device, &lt;parm0&gt; &lt;parm1&gt; are arbitrary parameters.
  1923. The module will analyze the sentence passed an isolate a device to be addressed, a place identifier,
  1924. a verb, a target and its value from the sentence passed.
  1925. If a proper command has been stored with device, place, verb and target, it will be subject to substitutions and then will be executed.
  1926. In these substitutions, a string $VALUE will be replaced by the value for the target reading, a string $DEV will be replaced by the device name identified by Babble,
  1927. and strings $PARM[0|1|2...] will be replaced by the
  1928. corresponding parameters passed to the function <code>Babble_DoIt</code>
  1929. <ul>
  1930. <li>If no stored command ist found, the sentence is passed to the local RiveScript interpreter if present</li>
  1931. <li>To have a FHEM register itself as a Babble Device, it must get an attribute value <code>babbleDevice=&lt;name&gt;</code>. The <i>name</i> parameter must either be
  1932. unique to the Babble system, or it muts be of the form <code>&lt;name&gt;_&lt;digits&gt;</code></li>
  1933. <li>Devices on remote FHEM installations are defined in the <code>babbleDevices</code> attribute, see below</li>
  1934. </ul>
  1935. <h4>Set</h4>
  1936. <ul>
  1937. <li><a name="babble_lock">
  1938. <code>set &lt;name&gt; locked</code><br />
  1939. <code>set &lt;name&gt; unlocked</code>
  1940. </a>
  1941. <br />sets the lockstate of the babble module to <i>locked</i> (i.e., babble setups
  1942. may not be changed) resp. <i>unlocked</i> (i.e., babble setups may be changed>)</li>
  1943. <li><a name="babble_save">
  1944. <code>set &lt;name&gt; save|restore</code>
  1945. </a>
  1946. <br />Manually save/restore the babble to/from the external file babbleFILE (save done automatically at each state modification, restore at FHEM start)</li>
  1947. <li><a name="babble_rivereload">
  1948. <code>set &lt;name&gt; rivereload</code>
  1949. </a>
  1950. <br />Reload data for RiveScript Interpreter</li>
  1951. <li><a name="babble_test">
  1952. <code>set &lt;name&gt; test</code>
  1953. </a>
  1954. <br />Run a few test cases for normalization</li>
  1955. </ul>
  1956. </ul>
  1957. <a name="babbleget"></a>
  1958. <h4>Get</h4>
  1959. <ul>
  1960. <li><a name="babble_version"></a>
  1961. <code>get &lt;name&gt; version</code>
  1962. <br />Display the version of the module</li>
  1963. <li><a name="babble_tokens"></a>
  1964. <code>get &lt;name&gt; tokens</code>
  1965. <br />Obtain fresh csrfToken from remote FHEM installations (needed after restart of remote FHEM)</li>
  1966. </ul>
  1967. <a name="babbleattr"></a>
  1968. <h4>Attributes</h4>
  1969. <ul>
  1970. <li><a name="babbleDevices"><code>attr &lt;name&gt; babbleDevices [&lt;babble devname&gt;:&lt;FHEM devname&gt;:1|2|3]* </code></a>
  1971. <br />space separated list of <i>remote</i> FHEM devices, each as a group separated by ':' consisting of
  1972. <ul><li>a Babble device name</li>
  1973. <li>a FHEM Device name</li>
  1974. <li>an integer 1..3, indication which of the <i>remoteFHEM</i> functions to be called</li>
  1975. </ul>
  1976. The Babble device name may contain a <b>*</b>-character. If this is the case, it will be considered a regular expression, with the star replaced by <b>(.*)</b>.
  1977. When using Babble with a natural language sentence whose device part matches this regular expression, the character group addressed by the star sequence is placed in the variable
  1978. <code>$STAR</code>, and used to replace this value in the command sequence.
  1979. </li>
  1980. <li><a name="helpFunc"><code>attr &lt;name&gt; helpFunc &lt;function name&rt;</code></a>
  1981. <br/>name of a help function which is used in case no command is found for a certain device. When this function is called, the strings $DEV, $HELP, $PARM[0|1|2...]
  1982. will be replaced by the devicename identified by Babble, the help text for this device and parameters passed to the Babble_DoIt function</li>
  1983. <li><a name="testParm"><code>attr &lt;name&gt; testParm(0|1|2|3) &lt;string&rt;</code></a>
  1984. <br/>if a command is not really excuted, but only tested, the values of these attributes will be used to substitute the strings $PARM[0|1|2...]
  1985. in the tested command</li>
  1986. <li><a name="dnuFile"><code>attr &lt;name&gt; dnuFile &lt;filename&rt;</code></a>
  1987. <br/>if this filename is given, every sentence that could not be analyzed is stored in this file</li>
  1988. <li><a name="confirmFunc"><code>attr &lt;name&gt; confirmFunc &lt;function name&rt;</code></a>
  1989. <br/>name of a confirmation function which is used in case a command is exceuted. When this function is called, the strings $DEV, $HELP, $PARM[0|1|2...]
  1990. will be replaced by the devicename identified by Babble, the help text for this device and parameters passed to the Babble_DoIt function</li>
  1991. <li><a name="noChatBot"><code>attr &lt;name&gt; noChatBot 0|1</code></a>
  1992. <br/>if this attribute is set to 1, a local RiveScript interpreter will be ignored even though it is present in the system</li>
  1993. <li><a name="remoteFHEM"><code>attr &lt;name&gt; remoteFHEM(0|1|2|3) [&lt;user&gt;:&lt;password&gt;@]&lt;IP address:port&rt;</code></a>
  1994. <br/>IP address and port for a remote FHEM installation</li>
  1995. <li><a name="remoteFunc"><code>attr &lt;name&gt; remoteFunc(0|1|2|3) &lt;function name&rt;</code></a>
  1996. <br/>name of a Perl function that is called for addressing a certain remote FHEM device</li>
  1997. <li><a name="remoteToken"><code>attr &lt;name&gt; remoteToken(0|1|2|3) &lt;csrfToken&rt;</code></a>
  1998. <br/>csrfToken for addressing a certain remote FHEM device</li>
  1999. <li><a name="babbleIds"><code>attr &lt;name&gt; babbleIds <id_1> <id_2> ...</code></a>
  2000. <br />space separated list of identities by which babble may be addressed</li>
  2001. <li><a name="babblePreSubs"><code>attr &lt;name&gt; babbleSubs <regexp1>:<replacement1>,<regexp2>:<replacement2>, ...</code></a>
  2002. <br/>space separated list of regular expressions and their replacements - this will be used on the initial sentence submitted to Babble
  2003. (Note: a space in the regexp must be replaced by \s). </li>
  2004. <li><a name="babblePlaces"><code>attr &lt;name&gt; babblePlaces <place_1> <place_2> ...</code></a>
  2005. <br />space separated list of special places to be identified in speech</li>
  2006. <li><a name="babbleNotPlaces"><code>attr &lt;name&gt; babbleNoPlaces <place_1> <place_2> ...</code></a>
  2007. <br />space separated list of rooms (in the local FHEM device) that should <i>not</i> appear in the list of place</li>
  2008. <li><a name="babbleStatus"><code>attr &lt;name&gt; babbleStatus <status_1> <status_2> ...</code></a>
  2009. <br />space separated list of status identifiers to be identified in speech. Example: <code>Status Value Weather Time</code></li>
  2010. <li><a name="babblePrepos"><code>attr &lt;name&gt; babblePrepos <prepo_1> <prepo_2> ...</code></a>
  2011. <br />space separated list of prepositions to be identified in speech. Example: <code>by in at on</code></li>
  2012. <li><a name="babbleTimes"><code>attr &lt;name&gt; babbleTimes <time_1> <time_2> ...</code></a>
  2013. <br />space separated list of temporal adverbs. Example: <code>today tomorrow</code></li>
  2014. <li><a name="babbleQuests"><code>attr &lt;name&gt; babbleQuests <pron_1> <pron_2> ...</code></a>
  2015. <br />space separated list of questioning adverbs. Example: <code>how when where</code></li>
  2016. <li><a name="babbleArticles"><code>attr &lt;name&gt; babbleArticles <art_1> <art_2> ...</code></a>
  2017. <br />space separated list of articles to be identified in speech. Example: <code>the</code></li>
  2018. <li><a name="babbleVerbs"><code>attr &lt;name&gt; babbleVerbs <form1a>,<form1b>...:<infinitive1> <form2a>,<form2b>...:<infinitive2></code></a>
  2019. <br />space separated list of verb groups to be identified in speech. Each group consists of comma separated verb forms (conjugations as well as variations),
  2020. followed by a ':' and then the infinitive form of the verb. Example: <code>speak,speaks,say,says:speaking</code></li>
  2021. <li><a name="babbleWrites"><code>attr &lt;name&gt; babbleWrites <write_1> <write_2> ...</code></a>
  2022. <br />space separated list of write verbs to be identified in speech. Example: <code>send add remove</code></li>
  2023. <li><a name="babbleVerbParts"><code>attr &lt;name&gt; babbleVerbParts <vp_1> <vp_2> ...</code></a>
  2024. <br />space separated list of verb parts to be identified in speech. Example: <code>un re</code></li>
  2025. <li><a name="babble_linkname"><code>attr &lt;name&gt; linkname
  2026. &lt;string&gt;</code></a>
  2027. <br />Name for babble web link, default:
  2028. babbles</li>
  2029. <li><a name="babble_hiddenroom"><code>attr &lt;name&gt; hiddenroom
  2030. &lt;string&gt;</code></a>
  2031. <br />Room name for hidden babble room (containing only the Babble device), default:
  2032. babbleRoom</li>
  2033. <li><a name="babble_publicroom"><code>attr &lt;name&gt; publicroom
  2034. &lt;string&gt;</code></a>
  2035. <br />Room name for public babble room (containing sensor/actor devices), default:
  2036. babble</li>
  2037. <li><a name="babble_lockstate"><code>attr &lt;name&gt; lockstate
  2038. locked|unlocked</code></a>
  2039. <br /><i>locked</i> means that babble setups may not be changed, <i>unlocked</i>
  2040. means that babble setups may be changed></li>
  2041. </ul>
  2042. </ul>
  2043. =end html
  2044. =begin html_DE
  2045. <a name="Babble"></a>
  2046. <h3>Babble</h3>
  2047. <ul>
  2048. <a href="https://wiki.fhem.de/wiki/Modul_Babble">Deutsche Dokumentation im Wiki</a> vorhanden, die englische Version gibt es hier: <a href="/fhem/docs/commandref.html#babble">babble</a>
  2049. </ul>
  2050. =end html_DE
  2051. =cut