Raspberry Pi Sprachsteuerung mit Node-RED, voice2json und openHAB 2
In diesem Beitrag erstellen wir eine Raspberry Pi Sprachsteuerung mit Node-RED. Ihr erfahrt welche Hardware und Software benötigt wird. Viel Spaß mit dieser Schritt für Schritt Anleitung.
Raspberry Pi Sprachsteuerung mit Node-RED – Hardware
Als Hardware für die Steuerung empfehle ich ein Raspberry Pi 4 und ein Respeaker Mic 2.0 Mirkofon.
Raspberry Pi Sprachsteuerung mit Node-RED – Software
Software – Node-RED installieren
Als erstes müsst ihr Node-RED auf dem Raspberry Pi installieren. Folgt hierzu einfach dem Beitrag Node-RED auf Raspberry Pi installieren.
Ich gehe davon aus, dass ihr weiterhin per ssh auf dem Raspberry Pi eingeloggt seid. Falls nicht loggt euch bitte ein.
Plant ihr den Raspberry Pi mittels WLAN einzubinden. Hierfür über den Befehl sudo raspi-config
das Menü aufrufen und Network Options, Wireless LAN wählen. Dort durchläuft einfach die einzelnen Schritte. Ist im Grunde selbsterklärend.
Im nächsten Schritt stellt die Sprache ein. Wir benötigen dies für eine deutsche Sprachsteuerung.
- Wählt Punkt 4. „Localisation Options Set up language …“
- Nun den Unterpunkt I1 „Change Locale Set up language …“
- Hier müsst ihr eine ganze weile Pfeil nach unten drücken bis ihr den Eintrag „de_DE.UTF-8 UTF-8“ findet. Dies mit der Leertaste markieren, Tab drücken, Enter und einfach weiter durch navigieren.
Software – Voice2JSON installieren
Als weitere Komponeten benötigen wir Voice2JSON. Ruft die folgende Seite auf.
http://voice2json.org/install.html#debian-package
Hier wählt das entsprechende Paket und macht einen Rechtsklick (1) auf den Link. Im Kontextmenü (2) „Adresse des Links kopieren“ wählen. Und ja, armhf ist richtig, auch wenn arm64 den PI 3+,4 listet.

Nun auf dem Pi wget
gefolgt von der kopierten Adresse eingeben. In unserem Fall (Pi4) sieht dies wie folgt aus.
1 | wget https://github.com/synesthesiam/voice2json/releases/download/v2.0/voice2json_2.0_armhf.deb |
Nun entpacken wir das Paket mit folgendem Befehl und beantwortet alle Fragen mit „Y“.
1 | sudo apt install ./voice2json_2.0_armhf.deb |
Sprache herunterladen unter folgendem Link. Da Kaldi aktuell die beste Kombination aus Erkennung und Performance bietet, laden wir das Paket de_kaldi-zamia-2.0.tar.gz herunter.
1 | http://voice2json.org/#supported-languages |
1 | wget https://github.com/synesthesiam/de_kaldi-zamia/archive/v2.0.tar.gz |
Entpacken der Sprachdateien.
1 | tar -xzvf v2.0.tar.gz |
Software – SoX installieren
Um mit Sound zu arbeiten benötigen wir noch Sox (Sound-Exchange). Dies könnt ihr bei Debian einfach über folgenden Befehl installieren.
1 | sudo apt-get install sox |
Software – Node-RED Raspberry Pi Sprachsteuerung Nodes
Nun benötigen wir noch die Nodes der für die Sprachsteuerung. Installiert als erstes GIT
1 | sudo apt-get install git |
Zur Installation der Nodes wechselt in das Node-RED Verzeichnis
1 | cd $HOME/.node-red |
Im Anschluss installiert ihr die folgenden beiden nodes. Diese Nodes hat übrigens unser Mitglied Johannes von myfreelife e.V. erstellt. Danke Johannes für diese schlanke, hervorragende Lösung!
1 | npm install johanneskropf/node-red-contrib-sox-utils |
1 | npm install johanneskropf/node-red-contrib-voice2json |
Startet node-RED per node-red-start
und als bestes per Service.
1 | sudo systemctl enable nodered.service |
Node-RED Sprachsteuerung Nodes
Verbindet nun das Respeaker USB Mirko per Kabel mit dem USB Port des Raspberry Pi. Alle LEDs sollten direkte anfangen zu leuchten und bereits auf Sprache reagieren.
Hinweis: Die folgenden Sprachsteuerung beruht auf openHAB 2 als Smarthome Server. Falls ihr andere Lösungen wie ioBroker, FHEM, Home Assistant und weiteres nutzt, müsst ihr den Flow entsprechend anpassen.
Bei der Erstellung des Flows hat mich Johannes unterstützt. Damit ihr es einfacher habt, kopiert euch einfach den Flow in den Zwischenspeicher.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 | [ { "id": "db234a3a.20fea8", "type": "subflow", "name": "RestItemOutBlank", "info": "", "category": "Openhab", "in": [ { "x": 80, "y": 60, "wires": [ { "id": "ea72e050.af37c" } ] } ], "out": [ { "x": 520, "y": 60, "wires": [ { "id": "11d6666a.4dbdaa", "port": 0 } ] } ], "env": [ { "name": "Url", "type": "str", "value": "http://localhost:8080", "ui": { "label": { "en-US": "Openhab Url" }, "type": "input", "opts": { "types": [ "str" ] } } } ], "color": "#C0DEED", "icon": "font-awesome/fa-sign-out", "status": { "x": 840, "y": 120, "wires": [ { "id": "4740b8d8.517638", "port": 0 }, { "id": "8fc663ec.2924f", "port": 0 } ] } }, { "id": "ea72e050.af37c", "type": "function", "z": "db234a3a.20fea8", "name": "RequestVars", "func": "const url = env.get(\"Url\");\nmsg.url = url + \"/rest/items/\" + msg.item + \"/\";\nmsg.headers = {};\nmsg.headers['Content-Type'] = 'text/plain';\nmsg.headers['Accept'] = 'application/json';\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "x": 210, "y": 60, "wires": [ [ "11d6666a.4dbdaa" ] ] }, { "id": "11d6666a.4dbdaa", "type": "http request", "z": "db234a3a.20fea8", "name": "", "method": "POST", "ret": "txt", "paytoqs": "ignore", "url": "", "tls": "", "persist": false, "proxy": "", "authType": "", "x": 390, "y": 60, "wires": [ [ "3d5a938e.bf762c" ] ] }, { "id": "3d5a938e.bf762c", "type": "switch", "z": "db234a3a.20fea8", "name": "", "property": "statusCode", "propertyType": "msg", "rules": [ { "t": "eq", "v": "200", "vt": "num" }, { "t": "else" } ], "checkall": "true", "repair": false, "outputs": 2, "x": 550, "y": 120, "wires": [ [ "4740b8d8.517638" ], [ "8fc663ec.2924f" ] ] }, { "id": "4740b8d8.517638", "type": "trigger", "z": "db234a3a.20fea8", "name": "", "op1": "{\"fill\":\"green\",\"shape\":\"dot\"}", "op2": " ", "op1type": "json", "op2type": "str", "duration": "1", "extend": true, "units": "s", "reset": "", "bytopic": "all", "outputs": 1, "x": 700, "y": 120, "wires": [ [] ] }, { "id": "8fc663ec.2924f", "type": "trigger", "z": "db234a3a.20fea8", "name": "", "op1": "{\"fill\":\"red\",\"shape\":\"dot\"}", "op2": " ", "op1type": "json", "op2type": "str", "duration": "1", "extend": true, "units": "s", "reset": "", "bytopic": "all", "outputs": 1, "x": 700, "y": 180, "wires": [ [] ] }, { "id": "9f69ee30.2ec97", "type": "tab", "label": "LocalVoice", "disabled": false, "info": "" }, { "id": "18ca7c6e.a2e434", "type": "sox-record", "z": "9f69ee30.2ec97", "name": "", "buttonStart": "msg", "inputs": 1, "inputSource": "1,0", "byteOrder": "-L", "encoding": "signed-integer", "channels": 1, "rate": 16000, "bits": 16, "gain": "0", "lowpass": 8000, "showDuration": false, "durationType": "forever", "durationLength": 0, "silenceDetection": "nothing", "silenceDuration": "2.0", "silenceThreshold": "2.0", "outputFormat": "stream", "manualPath": "", "debugOutput": false, "x": 150, "y": 280, "wires": [ [ "47a1e6ee.4462d8" ], [] ] }, { "id": "47a1e6ee.4462d8", "type": "voice2json-wait-wake", "z": "9f69ee30.2ec97", "name": "", "voice2JsonConfig": "fd76f088.e4c66", "inputField": "payload", "controlField": "control", "outputField": "payload", "nonContinousListen": true, "x": 380, "y": 280, "wires": [ [ "a718728f.487f4", "eea2d822.4011a8" ], [ "2f0150b9.dd289" ] ] }, { "id": "a718728f.487f4", "type": "debug", "z": "9f69ee30.2ec97", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 610, "y": 220, "wires": [] }, { "id": "c81bee83.d3e09", "type": "voice2json-training", "z": "9f69ee30.2ec97", "name": "", "voice2JsonConfig": "fd76f088.e4c66", "inputField": "payload", "outputField": "payload", "loadedProfile": "", "x": 370, "y": 500, "wires": [ [ "83dedab3.c18eb8", "85de8340.ac046", "3d6e07c7.254a78" ] ] }, { "id": "16f0a80.dbb9d58", "type": "inject", "z": "9f69ee30.2ec97", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "train", "payloadType": "str", "x": 160, "y": 500, "wires": [ [ "c81bee83.d3e09", "38ded18a.d4105e" ] ] }, { "id": "83dedab3.c18eb8", "type": "debug", "z": "9f69ee30.2ec97", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 590, "y": 500, "wires": [] }, { "id": "85de8340.ac046", "type": "file", "z": "9f69ee30.2ec97", "name": "", "filename": "/home/pi/training.txt", "appendNewline": true, "createDir": false, "overwriteFile": "true", "encoding": "none", "x": 610, "y": 540, "wires": [ [] ] }, { "id": "2f0150b9.dd289", "type": "voice2json-transcribe-stream", "z": "9f69ee30.2ec97", "name": "", "voice2JsonConfig": "fd76f088.e4c66", "inputField": "payload", "outputField": "payload", "x": 670, "y": 280, "wires": [ [ "287e72ff.75511e", "44a220e4.28b55" ] ] }, { "id": "4047cdae.b3f6f4", "type": "debug", "z": "9f69ee30.2ec97", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 1530, "y": 220, "wires": [] }, { "id": "287e72ff.75511e", "type": "change", "z": "9f69ee30.2ec97", "name": "", "rules": [ { "t": "set", "p": "control", "pt": "msg", "to": "listen", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 670, "y": 380, "wires": [ [ "47a1e6ee.4462d8" ] ] }, { "id": "44a220e4.28b55", "type": "voice2json-tti", "z": "9f69ee30.2ec97", "name": "", "voice2JsonConfig": "fd76f088.e4c66", "inputField": "payload.text", "controlField": "control", "outputField": "payload", "autoStart": true, "x": 940, "y": 280, "wires": [ [ "ff198956.161b68", "de126189.fc94f" ] ] }, { "id": "22ea7572.9f805a", "type": "inject", "z": "9f69ee30.2ec97", "name": "", "props": [ { "p": "control", "v": "start", "vt": "str" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "x": 900, "y": 380, "wires": [ [ "44a220e4.28b55" ] ] }, { "id": "bffdb5b4.05a0c8", "type": "subflow:db234a3a.20fea8", "z": "9f69ee30.2ec97", "name": "openHAB", "env": [ { "name": "Url", "value": "http://oh2:8080", "type": "str" } ], "x": 1560, "y": 280, "wires": [ [ "4e30d3e6.e58c4c", "2233ac63.7b7814" ] ] }, { "id": "3a27470d.f15c48", "type": "change", "z": "9f69ee30.2ec97", "name": "", "rules": [ { "t": "move", "p": "payload", "pt": "msg", "to": "original", "tot": "msg" }, { "t": "set", "p": "payload", "pt": "msg", "to": "original.slots.command", "tot": "msg" }, { "t": "set", "p": "item", "pt": "msg", "to": "original.slots.item", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1360, "y": 280, "wires": [ [ "4047cdae.b3f6f4", "bffdb5b4.05a0c8" ] ] }, { "id": "4e30d3e6.e58c4c", "type": "debug", "z": "9f69ee30.2ec97", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 1710, "y": 280, "wires": [] }, { "id": "68ab16fa.60cc78", "type": "inject", "z": "9f69ee30.2ec97", "name": "", "props": [ { "p": "control", "v": "stop", "vt": "str" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payloadType": "str", "x": 160, "y": 360, "wires": [ [ "47a1e6ee.4462d8" ] ] }, { "id": "eea2d822.4011a8", "type": "change", "z": "9f69ee30.2ec97", "name": "TonSpielen", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "bing1.wav", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 630, "y": 120, "wires": [ [ "5f8094bf.4bb46c" ] ] }, { "id": "2233ac63.7b7814", "type": "change", "z": "9f69ee30.2ec97", "name": "bing2.wav", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "bing2.wav", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1720, "y": 140, "wires": [ [ "5f8094bf.4bb46c" ] ] }, { "id": "b5e2e51f.eec2a8", "type": "comment", "z": "9f69ee30.2ec97", "name": "Local Speech", "info": "", "x": 130, "y": 80, "wires": [] }, { "id": "ff198956.161b68", "type": "switch", "z": "9f69ee30.2ec97", "name": "", "property": "payload.intent.name", "propertyType": "msg", "rules": [ { "t": "eq", "v": "Licht", "vt": "str" }, { "t": "eq", "v": "beispiel", "vt": "str" } ], "checkall": "true", "repair": false, "outputs": 2, "x": 1150, "y": 280, "wires": [ [ "3a27470d.f15c48" ], [ "de126189.fc94f" ] ] }, { "id": "de126189.fc94f", "type": "debug", "z": "9f69ee30.2ec97", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1350, "y": 360, "wires": [] }, { "id": "c36db8a4.723f18", "type": "inject", "z": "9f69ee30.2ec97", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": true, "onceDelay": "1", "topic": "", "payload": "start", "payloadType": "str", "x": 110, "y": 140, "wires": [ [ "18ca7c6e.a2e434" ] ] }, { "id": "5f8094bf.4bb46c", "type": "sox-play", "z": "9f69ee30.2ec97", "name": "", "outputDevice": "0,0", "gain": "20", "startNew": "queue", "debugOutput": true, "x": 1720, "y": 60, "wires": [ [] ] }, { "id": "38ded18a.d4105e", "type": "change", "z": "9f69ee30.2ec97", "name": "", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "stop", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 370, "y": 420, "wires": [ [ "18ca7c6e.a2e434" ] ] }, { "id": "3d6e07c7.254a78", "type": "change", "z": "9f69ee30.2ec97", "name": "", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": " sudo systemctl restart nodered.service", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 610, "y": 600, "wires": [ [ "ba4c88dd.cfb568" ] ] }, { "id": "ba4c88dd.cfb568", "type": "exec", "z": "9f69ee30.2ec97", "command": "", "addpay": true, "append": "", "useSpawn": "false", "timer": "", "oldrc": false, "name": "", "x": 800, "y": 600, "wires": [ [], [ "94d883bc.cee93" ], [] ] }, { "id": "94d883bc.cee93", "type": "debug", "z": "9f69ee30.2ec97", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 970, "y": 600, "wires": [] }, { "id": "fd76f088.e4c66", "type": "voice2json-config", "z": "", "profilePath": "/home/pi/de_kaldi-zamia-2.0", "name": "Kaldi_Deutsch", "sentences": "[Licht]\ncommands = (an:ON | ein:ON | einschalten:ON | anschalten:ON | aus:OFF | ausschalten:OFF){command}\n($items) (<commands>)\nschalte ($items) [(an:ON | aus:OFF){command}]", "slots": [ { "fileName": "items", "managedBy": "nodered", "fileContent": "([die] dachboden lampe){item: dg_l_lampe}\n([das] licht auf dem dachboden){item: dg_l_lampe}\n([das] dachboden licht){item: dg_l_ring}\n([den] ledring auf dem dachboden){item: dg_l_ring}\n(wohnzimmer lampe){item: dg_l_lampe}\n(schlafzimmer lampe){item: dg_l_ring}", "executable": false } ], "removeSlots": true } ] |
Im Anschluss geht in die Node-RED Oberfläche und importiert den Flow. Klickt auf das Menü Icon (1) und wählt Import (2).

Fügt den kopierten Flow in die Box (1) ein und drückt Import (2).

Als nächstes müsst ihr einige wenige Einstellungen vornehmen.
Node-Red Sprachsteuerung Konfiguration
Nun müsst ihr die Konfiguration noch auf eure Bedürfnisse hin anpassen.
Node-Red Sprachsteuerung Konfiguration – openHAB Host
Wenn ihr wie ich openHAB nutzt, ersetzt als erstes den Hostnamen. Öffnet die Node (1), ändert den Host (2) auf euren Hostnamen und klickt Fertig (3). Im Anschluss werden die Befehle an die Rest API von openHAB 2 gesendet.

Node-Red Sprachsteuerung Konfiguration – Kaldi
Als erstes passt die Kaldi Konfiguration an. Klickt auf die Node (1) und im Anschluss auf den ändern Knopf (2).

Hier passt den Pfad zum Kaldi Verzeichnis (1) an. Hier könnt ihr weiterhin einzelne Intents anlegen und die Steuerung für die Sprachbefehle definieren (2).

Eine detaillierte Erklärung zur Syntax gibt es im voice2json whitepaper.
Nun ist es noch wichtig, dass ihr die Slots aufruft (1) und mit dem Bleistift (2) die Konfiguration aufruft und an eure Bedarfe anpasst (3). Zur Erklärung ein Beispiel anhand der Zeilen vorhanden Beispielzeilen. In den runden Klammern steht der Text wie ich das Gerät ansprechen möchte. Ich kann also dachboden lampe, licht auf dem dachboden usw. sagen. In eckigen Klarmmern steht ein optionales Wort. So ist es egal, ob ich das dachboden licht oder dachboden licht sage. In den geschweiften Klammern kommt der Item Namen rein.

Klickt nun oben rechts in der Node-RED UI auf deploy damit eure bisherigen Änderungen aktiviert werden.
Node-Red Sprachsteuerung Konfiguration – Training
Ein weitere wichtige Komponente ist das Training. Nach jeder Änderung der Kaldi Konfiguration müsst ihr ein Training durchführen und Node-RED neu starten. Ich habe den Flow daher so optimiert, dass die nötigen Schritte direkt ausgeführt werden. Klickt einfach auf train (1) und die Schritte laufen automatisiert ab.

Wartet einen Augenblick und ihr die Erkennung sollte funktionieren. Viel Spaß mit dem Ausbau eurer Konfiguration.
Es klappt was nicht? Lasst ein Kommentar da. Ich gebe die Kommentare manuell frei, daher nicht wundern, wenn es etwas dauert. 🙂
[…] 3.1 Raspberry Pi Sprachsteuerung mit Node-RED […]
Hallo, hab das ganze wie beschrieben installiert. Leider scheine ich was verkehrt zu machen. Also nachem ich die Nodes von Johannes Kropf installiert habe und nodered als Service gestartet ist – sehe ich leider keinen der voice-to-jason nodes. Auch nach dem importieren des Flows sehe ich als einzigen node ein OpenHab sonst nichts. Hast du irgendeine Idee, was ich verkehrt mache?
Hallo, Ich hab den ganzen setup nochmal gemacht. Mit reboot. Dann gings. Vieleicht war der rebott was fehlte.
Hallo Uwe, klasse. Danke für dein Rückmeldung. BG
Hallo Thomas,
erstmal vielen Dank für die Anleitung.
Mir ist aufgefallen das der NodeRed Flow unvollständig ist.
Könntest Du es bitte den vollständigen Flow einstellen?
Vielen Dank.
Hallo Christian,
danke für den Hinweis. Ich habe ihn nochmal exportiert und eingefügt. Hoffe es geht nun.
Beste Grüße
Thomas
Hallo Thomas,
ich habe mal weitergemacht. Allerdings erhalte ich beim Import des obigen flows nur ein paar wenige nodes.
OpenHAB und Subflow RestitemOutBlank – RequestVars, HTTP ANforderung, Switch und Auslöser 1s (2 mal).
Habs paarmal probiert. Immer geleich. Kann man da was flasch machen?
Hallo Uwe,
hab leider den Flow scheinbar nicht ganz rüber kopiert. Versuche es einfach noch mal.
Beste Grüße
Thomas
Ich will noch nachtragen:
Bin erste zwei Tage „node red“ Benutzer und entsprechen unwissend. Hab sonst immer nur C, C++ und sowas gemacht. Das „node red“ ist ja gigantisch gut. Ich hab ne ganz andere Harware als hier beschrieben : homematic. Hab schon ein parr nodes geschrieben, die die Geräteliste lesen und parsen. Das geht soweit gut.
Aber, bei der Sprachsteuerung wollte ich nicht gern das Rad neu erfinden.
Hab voher SNIPS benutzt. Ging auch gut. Aber nach der Sonos Übernahme: ende.
Hallo Thomas,
sicher das der Flow nun komplett ist. Ich habe auch das Problem, dass ich nur die Node „openhab“ und den subflow sehe. Die anderen Nodes, die in den Screenshots angedeutet sind, kann ich in dem gelisteten Flow nicht finden.
Danke für Deine Hilfe und auch diese tolle Seite.
Burkhard
Hallo Burkhard,
oh, man ich vermute den Webcache. Hab die Seite noch mal aus dem Cache genommen und den Import selbst getestet. Bitte versuche es noch mal.
Danke und Grüße
Thomas
Jetzt sieht es besser aus; deutlich mehr als die 193 Zeilen, die es gestern noch waren. Probiere es heute Abend aus. Danke schonmal.
Hallo,
ich arbeite schon längere Zeit mit raspi + nodered für meine eigene Smarthomelösung.
Leider funktioniert
npm install johanneskropf/node-red-contrib-sox-utils
nicht. Der raspi findet keine jason package.
Und nicht nur das, jetzt startet node-red nicht mehr, weil es auch die Daten für voice2json wartet.
Auch ein uninstall der beiden johanneskropf-nodes hat daran nichts geändert.
Das sieht nicht so gut aus.
War wohl nicht gut genug getestet.
Ich finde die Idee echt super. Könntet ihr das Setup vielleicht als Docker Image anbieten?
Hallo Eberhard,
das tut mir leid. Der Beitrag war für eine Neuinstallation gedacht. Ich habe oben einen Hinweis geschrieben. Hoffe du hast noch ein Backup gehabt. Es kann leider viele Ursachen haben. Hattst du dein System vorher aktualisiert bzw. welche Versionen (node…) waren bei dir installiert?
Grüße
Thomas
Hallo,
gibt es irgendwo zu dem Thema (voice2json) ein deutschsprachige Diskussionsplatform?
Ich habe z.b. festgestellt, dass viele meiner Worte unter „unkown_words.txt“ aufgeführt werden, da ich sie mit einem großen Anfangsbuchstaben geschrieben habe.
Über solche Dinge würde ich mich gerne austauschen.
Hey Thomas,
gibt es da jetzt einen Zaubertrick wie man das alte ReSpeaker 4Mic Array zum laufen bekommt. Hatte nur deine S.E.P.I.A. Anleitung gesehen und dann das 4Mic Array gekauft… jetzt benutzt ihr hier aber ein anderes Mic.
Gibt es einen weg wie ich das 4Mic Array auf meinem Pi4 damit auch nutzen kann.
Danke im Voraus.
Grüße
Andreas
Schönen guten Tag,
ich bin ziemlich neu in dem ganzen Metier und bräuchte Hilfe. Ich hab alles komplett so erledigt wie beschrieben.
Node-RED zeigt mir im importierten Flow an, dass voice2json unknown ist. Hab den Nachdeme ich sox (zeigte das selbe) gefixt habe, komme ich hier aber nicht weiter.
Hatte auch die Datei mal heruntergeladen und über Click installiert. Welche Möglichkeiten hätte ich denn noch, dass es funktionert?
LG Tina
Hallo,
vielen Dank für sie super Arbeit. Leider bin ich Anfänger und komme bei folgenden Fehler nicht weiter (Raspi 2, Buster mit ReSpeaker 4-Mic-Array ohne USB):
Command failed: voice2json –profile /home/pi/de_kaldi-zamia-2.0 train-profile
/usr/bin/voice2json: Zeile 14: 7265 Speicherzugriffsfehler „${prefix}/voice2json/voice2json“ „$@“
Das Mic geht prinzipiell (Test über arecord bzw. aplay).
Vielen Dank für einen Hinweis.
Viele Grüße,
Ingo
Würde mich auch interessieren, ob das funktioniert, diese Anleitung mit dem 4Mic Array. Lässt sich die Hardware so nicht ansprechen?
Hallo Thomas,
vorneweg ich kenne mich so gut wie gar nicht mit node-red aus. Jedenfalls sieht es für mich so aus, als ob im Grunde alles richtig funktioniert. Allerdings sendet der Openhab Flow keinen Body mit dem POST Request zum einschalten eines Geräts mit. Es Wird also ein Request an die URL „http://ip:8080/rest/item/…“ gesendet, jedoch ohne den POST Body, der den zu setzenden Status übermittelt. Dementsprechend wird bei Openhab auch nichts geändert. So sieht es zumindest für mich aus, da die Rquest URL im Debuglog korrekt ist. Irgendeine Idee wo das Problem liegen könnte?
Danke im Voraus
Grüße Alex
Gibt es Alternativen zu einem USB-Mikrofon? Ich würde gerne mehrere Mikrofone in unterschiedlichen Räumen verwenden.
Hi! Vielen Dank für diese Anleitung. Was muss ich denn an dem flow anpassen, um mit iobroker arbeiten zu können? Nur die ersten Zeilen? Oder wird das umfangreicher? Danke schon Mal! BG dominik
Hallo Thomas,
nachdem ich deine Anleitung gefunden habe, bin ich jetzt als kompletter Neuling und Nicht-Programmierer in diese Welt eingetaucht. Leider ging das Wochenende dadurch ziemlich schnell rum. Ich habe den klassischen Weg eingeschlagen: Einen Tag so lange rumkonfiguriert bis nichts mehr ging. Am zweiten Tag alles neu aufgesetzt (Openhab 3 + Node-Red), die Erfahrungen vom ersten Anlauf genutzt und siehe da: Alles funktioniert hervorragend. Die größte Herausforderung ist, die Kommandos für Openhab herauszufinden. Hue funktioniert bisher sehr gut. Nur bei der Steuerung von Rollos über Shelly 2.5. haperts noch etwas. Ich würde mich auf jeden Fall über mehr Inhalte zu diesem Thema freuen! Vielen Dank für diese kleine Einleitung! Beste Grüße.
Moin,
toller Beitrag, sehr gut erklärt, auch für Laien.
Ich würde gerne noch wissen ob ich auch mehrere Respeaker Mic 2.0 anschließen kann.
Beispielsweise zur überachung größer Räume.
Für die Überwachung mehrerer Räume wird es wohl sinnvoller sein seperate Einheiten (Raspberry + Respeaker) zu verbauen. Gibt es da erfahrungswerte?
Wie sieht es aus wenn der Pi auf mehrere, verschiedene Personen soll? Ich meine Wegen des Trainings…
Danke und Gruß
Flo
Hallo Thomas,
vielen Dank für deine wirklich sehr gut gemacht ANleitung! konnte soweit alles nachvollziehen. Im Node Red sehe ich, dass auch bereits auf Audio Input gewartet wird. Wahrscheinlich habe ich ein Brett vor dem Kopf – aber wo steht das WakeWord bzw. wo kann ich es verändern?
Vielen Dank
Michael
Hallo Thomas,
Habe folgende Situation habe Raspy4 gekauft auch das Mic aber Openhab läuft auf einer anderen IP Adresse nicht auf dem Raspy4 denke ist aber egal muss ich nur anpassen was ich gemacht habe!
Beim Kaldi Verzeichnis hab ich auch ein anderes nämlich dieses ist bei mir automatisch eingetragen : /home/pi/de_kaldi-zamia-2.0
hab auch die Items definiert mal ganz einfach nur eines:
(licht){item: Licht_OG_Wohn_Wand}
Bei „Voice2Json Wakeword“ steht darunter immer „waiting for audio“
hab auch schon zum 2. mal die Anleitung durch gemacht und beim 2. mal bei jeden Punkt einen Neustart gemacht aber ich sage „licht ein“ und es passiert nichts
oder muss ich da irgendein aktivierungs Wort vorher sagen wie beim Amazon Echo „Alexa“
Hoffe du kannst mir helfen!
Vielen Danke schon mal im Voraus
Hallo, ich habe alles installiert und aufgesetzt. Leider hinterlässt mich am Ende die Anleitung etwas ratlos. Also, wenn ich bei ‚train‘ was injiziere: und dann? Muss man dann irgendwas sagen? Bei mir steht dann unter dem Voice2Json training node ewig lang … training. Irgendwann stand dann mal success, aber wannn und weshalb weiss ich nicht. Ausserdem steht im Debug Fenster: not recording right now.
Jetzt steht es schon wieder seit ner halben Stunde auf ..training. Kann ich da irgendwas machen, dass es weitergeht?