Migrated 5th article
This commit is contained in:
parent
71b2a2f8aa
commit
6a4a902dbd
2 changed files with 190 additions and 0 deletions
BIN
static/img/arduino-1.gif
Normal file
BIN
static/img/arduino-1.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
|
@ -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 you’ll be able to control your music setup from there as well.
|
will appear in the bottom bar, and you’ll 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 I’ll show how
|
||||||
|
to turn it into a universal remote for controlling your music (and not only) with some Platypush automation. You’ll need
|
||||||
|
the following:
|
||||||
|
|
||||||
|
- An infrared receiver — they’re 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 doesn’t 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 you’ve 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, that’s 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, you’ve just built your own customizable and universal music remote!
|
||||||
|
|
||||||
|
## Voice assistant integration
|
||||||
|
|
||||||
|
A smart music setup isn’t really complete without a voice assistant integration. I’ve 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 you’ve 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. Let’s 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 won’t 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!
|
||||||
|
|
Loading…
Reference in a new issue