The gubbins and configuration files for integrating a McIntosh C2500 amplifier (it should work with all rs232 McIntosh's) with Home Assistant using ESPHome.
# Filename: mcintosh.yaml
substitutions:
device_name: mcintosh
friendly_name: "McIntosh C2500"
timezone: "Europe/London"
esphome:
name: ${device_name}
platform: ESP8266
board: d1_mini
includes:
- mcintosh_media_player.h
wifi:
ssid: iot
password: !secret wifi_password
ap:
ssid: ${friendly_name}_AP
logger:
level: VERBOSE
baud_rate: 0
hardware_uart: UART1
api:
reboot_timeout: 300s
ota:
platform: esphome
web_server:
port: 80
time:
- platform: homeassistant
id: homeassistant_time
timezone: ${timezone}
uart:
id: mcintosh_uart
tx_pin: D3
rx_pin: D4
baud_rate: 115200
custom_component:
- lambda: |-
auto mcintosh_player = new McIntoshMediaPlayer(id(mcintosh_uart));
App.register_component(mcintosh_player);
return {mcintosh_player};
id: mcintosh_player
sensor:
- platform: template
name: "McIntosh Volume"
lambda: |-
auto* player = static_cast<McIntoshMediaPlayer*>(id(mcintosh_player).get_component(0));
return player->get_volume() * 100.0f;
unit_of_measurement: "%"
icon: "mdi:volume-high"
update_interval: 60s
text_sensor:
- platform: template
name: "McIntosh Source"
lambda: |-
auto* player = static_cast<McIntoshMediaPlayer*>(id(mcintosh_player).get_component(0));
return player->get_source();
icon: "mdi:audio-input-rca"
update_interval: 60s
number:
- platform: template
name: "McIntosh Volume Control"
min_value: 0
max_value: 100
step: 1
lambda: |-
auto* player = static_cast<McIntoshMediaPlayer*>(id(mcintosh_player).get_component(0));
return player->get_volume() * 100.0f;
set_action:
lambda: |-
auto* player = static_cast<McIntoshMediaPlayer*>(id(mcintosh_player).get_component(0));
player->set_volume(x / 100.0f);
select:
- platform: template
name: "McIntosh Source Select"
options:
- "MC"
- "MM"
- "CD1"
- "CD2"
- "DVD"
- "AUX"
- "SERVER"
- "D2A"
- "TUNER_AM"
- "TUNER_FM"
initial_option: "MC"
optimistic: true
set_action:
lambda: |-
auto* player = static_cast<McIntoshMediaPlayer*>(id(mcintosh_player).get_component(0));
player->set_source(x);
button:
- platform: template
name: "McIntosh Volume Up"
icon: "mdi:volume-plus"
on_press:
lambda: |-
auto* player = static_cast<McIntoshMediaPlayer*>(id(mcintosh_player).get_component(0));
player->volume_up();
- platform: template
name: "McIntosh Volume Down"
icon: "mdi:volume-minus"
on_press:
lambda: |-
auto* player = static_cast<McIntoshMediaPlayer*>(id(mcintosh_player).get_component(0));
player->volume_down();
interval:
- interval: 60s
then:
lambda: |-
auto* player = static_cast<McIntoshMediaPlayer*>(id(mcintosh_player).get_component(0));
player->query_state();
switch:
- platform: template
name: "McIntosh Power"
icon: "mdi:power"
optimistic: true
turn_on_action:
lambda: |-
auto* player = static_cast<McIntoshMediaPlayer*>(id(mcintosh_player).get_component(0));
player->power_on();
turn_off_action:
lambda: |-
auto* player = static_cast<McIntoshMediaPlayer*>(id(mcintosh_player).get_component(0));
player->power_off();
// Filename: mcintosh_media_player.h
#pragma once
#include "esphome.h"
#include "esphome/core/component.h"
#include "esphome/components/uart/uart.h"
class McIntoshMediaPlayer : public Component {
public:
McIntoshMediaPlayer(uart::UARTComponent *parent) : uart_(parent) {}
void setup() override {
// Initial setup
query_state();
}
void loop() override {
if (uart_->available()) {
std::string response;
while (uart_->available()) {
uint8_t byte;
if (uart_->read_byte(&byte)) {
response += (char)byte;
}
}
process_response(response);
}
}
void query_state() {
uart_->write_str("(QRY)\r");
}
void set_volume(float volume) {
int vol = volume * 100;
char command[20];
sprintf(command, "(VST Z1 %d)\r", vol);
uart_->write_str(command);
}
void volume_up() {
uart_->write_str("(VUP Z1)\r");
}
void volume_down() {
uart_->write_str("(VDN Z1)\r");
}
void set_source(const std::string &source) {
int input = source_to_input(source);
char command[20];
sprintf(command, "(INP Z1 %d)\r", input);
uart_->write_str(command);
}
void power_on() {
uart_->write_str("(PON Z1)\r");
delay(100);
uart_->write_str("(PON Z1)\r");
}
void power_off() {
uart_->write_str("(POF Z1)\r");
}
float get_volume() const { return volume_; }
std::string get_source() const { return source_; }
protected:
uart::UARTComponent *uart_;
float volume_ = 0.0f;
std::string source_ = "UNKNOWN";
void process_response(const std::string &response) {
if (response.find("VST") != std::string::npos) {
// Process volume status
int vol;
if (sscanf(response.c_str(), "(VST Z1 %d)", &vol) == 1) {
volume_ = vol / 100.0f;
ESP_LOGD("McIntosh", "Volume updated: %.2f", volume_);
}
} else if (response.find("INP") != std::string::npos) {
// Process input status
int input;
if (sscanf(response.c_str(), "(INP Z1 %d)", &input) == 1) {
source_ = input_to_source(input);
ESP_LOGD("McIntosh", "Source updated: %s", source_.c_str());
}
}
}
std::string input_to_source(int input) {
switch (input) {
case 1: return "MC";
case 2: return "MM";
case 3: return "CD1";
case 4: return "CD2";
case 5: return "DVD";
case 6: return "AUX";
case 7: return "SERVER";
case 8: return "D2A";
case 9: return "TUNER_AM";
case 10: return "TUNER_FM";
default: return "UNKNOWN";
}
}
int source_to_input(const std::string &source) {
if (source == "MC") return 1;
if (source == "MM") return 2;
if (source == "CD1") return 3;
if (source == "CD2") return 4;
if (source == "DVD") return 5;
if (source == "AUX") return 6;
if (source == "SERVER") return 7;
if (source == "D2A") return 8;
if (source == "TUNER_AM") return 9;
if (source == "TUNER_FM") return 10;
return 1; // Default to MC if unknown
}
};
media_player:
- platform: universal
supported_features:
SUPPORT_VOLUME_SET |
SUPPORT_VOLUME_STEP |
SUPPORT_SELECT_SOURCE |
SUPPORT_TURN_ON |
SUPPORT_TURN_OFF
name: McIntosh C2500
volume_level: sensor.mcintosh_volume
volume_set: number.mcintosh_volume_control
source: sensor.mcintosh_source
source_select: select.mcintosh_source_select
turn_on: switch.mcintosh_power
turn_off: switch.mcintosh_power
attributes:
state: switch.mcintosh_power
commands:
play_pause:
service: media_player.media_play_pause
target:
entity_id: media_player.livingroom
volume_up:
service: number.set_value
data_template:
entity_id: number.mcintosh_volume_control
value: "{{ (states('number.mcintosh_volume_control') | float) + 1 }}"
volume_down:
service: number.set_value
data_template:
entity_id: number.mcintosh_volume_control
value: "{{ (states('number.mcintosh_volume_control') | float) - 1 }}"
select_source:
service: select.select_option
data_template:
entity_id: select.mcintosh_source_select
option: "{{ source }}"
turn_on:
service: switch.turn_on
target:
entity_id: switch.mcintosh_power
turn_off:
service: switch.turn_off
target:
entity_id: switch.mcintosh_power
type: vertical-stack
cards:
- type: entities
title: McIntosh Controls
entities:
- entity: switch.mcintosh_power
name: Power
- entity: number.mcintosh_volume_control
name: Volume
- type: button
name: Volume Up
tap_action:
action: call-service
service: number.set_value
service_data:
entity_id: number.mcintosh_volume_control
value: "{{ (states('number.mcintosh_volume_control') | float) + 1 }}"
- type: button
name: Volume Down
tap_action:
action: call-service
service: number.set_value
service_data:
entity_id: number.mcintosh_volume_control
value: "{{ (states('number.mcintosh_volume_control') | float) - 1 }}"
- entity: select.mcintosh_source_select
name: Source
Instructions:
- ESPHome:
- Create a new ESPHome project and replace the contents of the
mcintosh.yaml
file with the code provided above. - Create a new file named
mcintosh_media_player.h
and paste the C++ code. - Adjust the substitutions (device name, Wi-Fi credentials, MQTT broker) according to your environment.
- Flash the code to your ESP8266 device.
- Create a new ESPHome project and replace the contents of the
Notes:
- This integration assumes that your McIntosh C2500 amplifier is connected to the ESP8266 via RS232 on pins D3 (TX) and D4 (RX).
- The baud rate is set to 115200 in both the ESPHome and C++ code. Adjust if necessary.
- This code provides basic functionality for volume control, source selection, and power on/off. You can extend it to include other features supported by your McIntosh C2500 amplifier.