Migrated 5th article

This commit is contained in:
Fabio Manganiello 2021-01-28 20:59:57 +01:00
parent 71b2a2f8aa
commit 6a4a902dbd
2 changed files with 190 additions and 0 deletions

BIN
static/img/arduino-1.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -314,3 +314,193 @@ If you use Iris as a web interface to Mopidy you can now head to settings and en
will appear in the bottom bar, and youll be able to control your music setup from there as well. will appear in the bottom bar, and youll be able to control your music setup from there as well.
Time to enjoy your low-cost but powerful multi-room music setup! Time to enjoy your low-cost but powerful multi-room music setup!
## Build your remote to control the music
All of us have some unused infrared remote collecting dust somewhere in the living room. In this section Ill show how
to turn it into a universal remote for controlling your music (and not only) with some Platypush automation. Youll need
the following:
- An infrared receiver — theyre usually very cheap. Any of them will do, even though I personally
used [this model](https://www.banggood.in/Universal-IR-Infrared-Receiver-Head-With-Iron-Shell-TL1838-VS1838B-1838-38Khz-p-1204379.html?p=1L111111347088201706).
- An Arduino or Arduino-compatible device (or an ESP8266, or a RaspberryPi Pico, or any other microcontroller, although
the code may be different). Most of the infrared sensors around communicate over an analog interface, but
the RaspberryPi doesnt come with an ADC converter. The solution is to plug an Arduino over USB and let it monitor for
changes on the detected infrared signal.
- A breadboard.
Once youve got all the hardware you can set up your receiver:
- Plug the infrared receiver to GND and Vcc, and the data PIN to e.g. the Arduino PIN 2, as shown in the figure below:
![Arduino IR sensor connection](../img/arduino-1.gif)
- Download and install the Arduino [IRremote library](https://github.com/z3t0/Arduino-IRremote).
- Prepare a sketch that reads the data from the infrared receiver PIN and writes it over serial interface as a JSON:
```c
#include <IRremote.h>
// When a signal with all bits set to 1 is received it
// usually means that the previous pressed key is still
// being pressed, until a signal with all bits set to
// zero is received.
#define IR_REPEAT 0xFFFFFFFF
const int RECV_PIN = 2;
IRrecv irrecv(RECV_PIN);
decode_results results;
unsigned int latest_value = 0;
void setup(){
Serial.begin(9600);
irrecv.enableIRIn();
irrecv.blink13(true);
}
void send_value(unsigned int value) {
Serial.print("{\"ir\":");
Serial.print(value, HEX);
Serial.println("}");
}
void loop(){
if (irrecv.decode(&results)){
if (results.value == IR_REPEAT && latest_value != 0) {
send_value(latest_value);
} else if (results.value && results.value != latest_value) {
send_value(results.value);
}
latest_value = results.value;
irrecv.resume();
}
}
```
- Compile the sketch and upload it to the Arduino.
- Open the Arduino serial monitor and verify that you see the JSON string when you press a key on the remote.
- Enable the serial plugin and backend in your platypush configuration:
```yaml
serial:
device: /dev/ttyUSB0
backend.sensor.serial:
enabled: True
```
- Restart platypush, check the output and press a key on your remote. You should see an event in the logs that looks
like this:
```
INFO|platypush|Received event: {"type": "event", "target": "hostname", "origin": "hostname", "args": {"type": "platypush.message.event.sensor.SensorDataChangeEvent", "data": {"ir": "4b34d827"}}}
```
- Take note of the hexadecimal code reported on the event, thats the decoded data associated to that specific remote
button. Then add an event hook to deal with the actions to be run when a certain button is pressed:
```python
from platypush.config import Config
from platypush.event.hook import hook
from platypush.utils import run
from platypush.message.event.sensor import SensorDataChangeEvent
@hook(SensorDataChangeEvent)
def on_remote_key_press(event, **context):
ir_code = event.data.get('ir')
if not ir_code:
return
# Playback control logic
if ir_code == 'code1':
run('music.mpd.play')
elif ir_code == 'code2':
run('music.mpd.pause')
elif ir_code == 'code3':
run('music.mpd.stop')
elif ir_code == 'code5':
run('music.mpd.previous')
elif ir_code == 'code6':
run('music.mpd.next')
# ...
# Multi-room setup logic
elif ir_code == 'code7':
# Un-mute the stream to another host
run('music.snapcast.mute', host=Config.get('device_id'), client='some-client',
mute=False)
elif ir_code == 'code8':
# Mute the stream to another host
run('music.snapcast.mute', host=Config.get('device_id'), client='some-client',
mute=True)
```
Congratulations, youve just built your own customizable and universal music remote!
## Voice assistant integration
A smart music setup isnt really complete without a voice assistant integration. Ive covered
[in a previous article](https://blog.platypush.tech/article/Build-your-customizable-voice-assistant-with-Platypush) how
to set up platypush to turn your device into a full-featured Google Assistant. If youve managed to get your
assistant up and running, you can add some rules to control your music, play specific content, or synchronize your audio
stream to another room. Lets see a couple of examples:
```python
from platypush.config import Config
from platypush.event.hook import hook
from platypush.utils import run
from platypush.message.event.assistant import SpeechRecognizedEvent
@hook(SpeechRecognizedEvent, phrase='play (the)? music')
def on_music_play(*args, **context):
run('music.mpd.play')
@hook(SpeechRecognizedEvent, phrase='stop (the)? music')
def on_music_pause(*args, **context):
run('music.mpd.stop')
@hook(SpeechRecognizedEvent, phrase='play (the)? radio')
def on_play_radio(*args, **context):
run('music.mpd.play', resource='tunein:station:s13606')
@hook(SpeechRecognizedEvent, phrase='play playlist ${name}')
def on_play_playlist(event, name=None, **context):
run('music.mpd.load', resource=name)
@hook(SpeechRecognizedEvent, phrase='play ${title} by ${artist}')
def search_and_play_song(event, title=None, artist=None, **context):
results = run('music.mpd.search', artist=artist, title=title)
if results > 0:
run('music.mpd.play', resource=results[0]['file'])
@hook(SpeechRecognizedEvent, phrase='play (the)? music to (the)? bedroom')
def sync_music_to_bedroom(event, **context):
run('music.snapcast.mute', host=Config.get('device_id'), client='bedroom', mute=False)
run('music.snapcast.volume', host=Config.get('device_id'), client='bedroom', volume=90)
```
## Conclusions
The current situation when it comes to music streaming and multi-room setup in a home automation environment is still
extremely fragmented. Each commercial solution out there seems more interested in building its own walled garden, and a
proper multi-room setup usually comes with high costs and in most of the cases it wont be compatible with your existing
speakers. With the ingredients provided in this article you should be able to walk around most of these limitations and:
- Set up your multi-service music player controllable by any interface you like
- Set up your multi-room configuration that makes it possible to add a new room by simply adding one more RaspberryPi
- Use any existing infrared remote to control the music
- Integrate custom music actions into a voice assistant
With these foundations in place the only limit to what you can do with your new music set up comes from your own
imagination!