Set default config on configuration error to allow listing midi connections before configuration. Also fix MQTT configurations.

This commit is contained in:
James Coleman 2024-09-07 21:29:34 -05:00
parent 8fe0a0fb2f
commit 24ecc9870e
4 changed files with 106 additions and 21 deletions

View File

@ -110,7 +110,7 @@ On MacOS, there is an IAC Driver that can be enabled in Audio MIDI Setup.
midi_routers: midi_routers:
- name: service_notifications - name: service_notifications
device: IAC Driver Bus 1 device: IAC Driver Bus 1
debug_listener: true log_level: 1
``` ```
### Example note trigger configuration ### Example note trigger configuration
@ -120,7 +120,7 @@ midi_routers:
midi_routers: midi_routers:
- name: service_notifications - name: service_notifications
device: IAC Driver Bus 1 device: IAC Driver Bus 1
debug_listener: true log_level: 1
note_triggers: note_triggers:
- channel: 0 - channel: 0
note: 0 note: 0
@ -136,7 +136,7 @@ midi_routers:
midi_routers: midi_routers:
- name: service_notifications - name: service_notifications
device: IAC Driver Bus 1 device: IAC Driver Bus 1
debug_listener: true log_level: 1
request_triggers: request_triggers:
- channel: 0 - channel: 0
note: 0 note: 0
@ -152,7 +152,7 @@ midi_routers:
midi_routers: midi_routers:
- name: service_notifications - name: service_notifications
device: IAC Driver Bus 1 device: IAC Driver Bus 1
debug_listener: true log_level: 2
note_triggers: note_triggers:
- channel: 0 - channel: 0
note: 0 note: 0
@ -174,5 +174,82 @@ midi_routers:
headers: headers:
Content-Type: Content-Type:
- multipart/form-data; boundary=---------------------------888832887744 - multipart/form-data; boundary=---------------------------888832887744
debug_request: true ```
### Example mqtt config
```yaml
---
midi_routers:
- name: Wing Midi Signals
device: WING Port 4
mqtt:
host: 10.0.0.2
port: 1883
client_id: midi_mqtt_bridge
user: mqtt
password: password
topic: midi/behringer_wing
log_level: 3
note_triggers:
- channel: 0
note: 1
match_all_velocities: true
mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val
mqtt_payload:
- "1"
- channel: 0
note: 2
match_all_velocities: true
mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val
mqtt_payload:
- "2"
- channel: 0
note: 3
match_all_velocities: true
mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val
mqtt_payload:
- "3"
- channel: 0
note: 4
match_all_velocities: true
mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val
mqtt_payload:
- "4"
- channel: 0
note: 5
match_all_velocities: true
mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val
mqtt_payload:
- "5"
- channel: 0
note: 6
match_all_velocities: true
mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val
mqtt_payload:
- "6"
- channel: 0
note: 7
match_all_velocities: true
mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val
mqtt_payload:
- "7"
- channel: 0
note: 8
match_all_velocities: true
mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val
mqtt_payload:
- "8"
- channel: 0
match_all_notes: true
match_all_velocities: true
mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/bu/val
mqtt_payload:
- "1"
- channel: 0
match_all_notes: true
match_all_velocities: true
mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/bu/val
mqtt_payload:
- "0"
``` ```

View File

@ -48,7 +48,7 @@ func (a *App) ReadConfig() {
} else if _, err := os.Stat(etcConfig); err == nil { } else if _, err := os.Stat(etcConfig); err == nil {
configFile = etcConfig configFile = etcConfig
} else { } else {
log.Fatal("Unable to find a configuration file.") log.Println("Unable to find a configuration file.")
} }
// Load the configuration file. // Load the configuration file.
@ -68,6 +68,7 @@ func (a *App) ReadConfig() {
fig.Dirs(filePath), fig.Dirs(filePath),
) )
if err != nil { if err != nil {
app.config = config
log.Printf("Error parsing configuration: %s\n", err) log.Printf("Error parsing configuration: %s\n", err)
return return
} }

View File

@ -15,7 +15,7 @@ import (
const ( const (
serviceName = "midi-request-trigger" serviceName = "midi-request-trigger"
serviceDescription = "Takes trigger MIDI messages by HTTP or MQTT requests and trigger HTTP or MQTT requests by MIDI messages" serviceDescription = "Takes trigger MIDI messages by HTTP or MQTT requests and trigger HTTP or MQTT requests by MIDI messages"
serviceVersion = "0.2" serviceVersion = "0.2.1"
) )
// App is the global application structure for communicating between servers and storing information. // App is the global application structure for communicating between servers and storing information.

View File

@ -70,12 +70,14 @@ type MQTTPayload struct {
// Triggers that occur from MIDI messages received. // Triggers that occur from MIDI messages received.
type NoteTrigger struct { type NoteTrigger struct {
// If set, every note played will be matched.
MatchAllNotes bool `fig:"match_all_notes"`
// Channel to match. // Channel to match.
Channel uint8 `fig:"channel"` Channel uint8 `fig:"channel"`
// If we should match all channel values.
MatchAllChannels bool `fig:"match_all_channels"`
// Note to match. // Note to match.
Note uint8 `fig:"note"` Note uint8 `fig:"note"`
// If we should match all note values.
MatchAllNotes bool `fig:"match_all_notes"`
// Velocity to match. // Velocity to match.
Velocity uint8 `fig:"velocity"` Velocity uint8 `fig:"velocity"`
// If we should match all velocity values. // If we should match all velocity values.
@ -83,7 +85,7 @@ type NoteTrigger struct {
// Custom MQTT message. Do not set to ignore MQTT. // Custom MQTT message. Do not set to ignore MQTT.
MqttTopic string `fig:"mqtt_topic"` MqttTopic string `fig:"mqtt_topic"`
// Nil payload will generate a payload with midi info. // Nil payload will generate a payload with midi info.
MqttPayload []interface{} `fig:"mqtt_payload"` MqttPayload interface{} `fig:"mqtt_payload"`
// If the HTTP request should includ midi info. // If the HTTP request should includ midi info.
MidiInfoInRequest bool `fig:"midi_info_in_request"` MidiInfoInRequest bool `fig:"midi_info_in_request"`
// Should SSL requests require a valid certificate. // Should SSL requests require a valid certificate.
@ -133,17 +135,17 @@ type MidiRouter struct {
// How much logging. // How much logging.
// 0 - Errors // 0 - Errors
// 1 - MQTT and OSC receive logging. // 1 - MQTT, HTTP, and MIDI receive logging.
// 2 - MQTT and OSC send logging. // 2 - MQTT, HTTP, and MIDI send logging.
// 3 - Debug // 3 - Debug
LogLevel LogLevel `yaml:"log_level" json:"log_level"` LogLevel LogLevel `fig:"log_level"`
// Connection to MIDI device. // Connection to MIDI device.
MidiOut drivers.Out `fig:"-"` MidiOut drivers.Out `fig:"-"`
// Function to stop listening to MIDI device. // Function to stop listening to MIDI device.
ListenerStop func() `fig:"-"` ListenerStop func() `fig:"-"`
// The client connection to MQTT. // The client connection to MQTT.
MqttClient mqtt.Client `yaml:"-" json:"-"` MqttClient mqtt.Client `fig:"-"`
} }
// Logging function to allow log levels. // Logging function to allow log levels.
@ -156,7 +158,7 @@ func (r *MidiRouter) Log(level LogLevel, format string, args ...interface{}) {
// When a MIDI message occurs, send the HTTP request. // When a MIDI message occurs, send the HTTP request.
func (r *MidiRouter) sendRequest(channel, note, velocity uint8) { func (r *MidiRouter) sendRequest(channel, note, velocity uint8) {
// If MQTT firehose not disabled, send to general cmd topic. // If MQTT firehose not disabled, send to general cmd topic.
if r.MQTT.Host != "" && r.MQTT.Port != 0 && !r.MQTT.DisableMidiFirehose { if r.MqttClient != nil && !r.MQTT.DisableMidiFirehose {
payload := MQTTPayload{ payload := MQTTPayload{
Channel: channel, Channel: channel,
Note: note, Note: note,
@ -168,7 +170,7 @@ func (r *MidiRouter) sendRequest(channel, note, velocity uint8) {
} else { } else {
topic := r.MQTT.Topic + "/cmd" topic := r.MQTT.Topic + "/cmd"
r.MqttClient.Publish(topic, 0, true, data) r.MqttClient.Publish(topic, 0, true, data)
r.Log(SendLog, "-> [MQTT] %s", topic) r.Log(SendLog, "-> [MQTT] %s: %s", topic, string(data))
} }
} }
@ -177,14 +179,19 @@ func (r *MidiRouter) sendRequest(channel, note, velocity uint8) {
// If match all notes, process this request. // If match all notes, process this request.
// If not, check if channel, note, and velocity matches. // If not, check if channel, note, and velocity matches.
// The velocity may be defined to accept all. // The velocity may be defined to accept all.
if trig.MatchAllNotes || (trig.Channel == channel && trig.Note == note && (trig.Velocity == velocity || trig.MatchAllVelocities)) { if (trig.Channel == channel || trig.MatchAllChannels) && (trig.Note == note || trig.MatchAllNotes) && (trig.Velocity == velocity || trig.MatchAllVelocities) {
// For all logging, we want to print the message so setup a common string to print. // For all logging, we want to print the message so setup a common string to print.
logInfo := fmt.Sprintf("note %s(%d) on channel %v with velocity %v", midi.Note(note), note, channel, velocity) logInfo := fmt.Sprintf("note %s(%d) on channel %v with velocity %v", midi.Note(note), note, channel, velocity)
if trig.MqttTopic != "" { if trig.MqttTopic != "" && r.MqttClient != nil {
if trig.MqttPayload != nil { if trig.MqttPayload != nil {
r.MqttClient.Publish(trig.MqttTopic, 0, true, trig.MqttPayload) data, err := json.Marshal(trig.MqttPayload)
r.Log(SendLog, "-> [MQTT] %s", trig.MqttTopic) if err != nil {
r.Log(ErrorLog, "Json Encode: %s", err)
} else {
r.MqttClient.Publish(trig.MqttTopic, 0, true, data)
r.Log(SendLog, "-> [MQTT] %s: %s", trig.MqttTopic, string(data))
}
} else { } else {
payload := MQTTPayload{ payload := MQTTPayload{
Channel: channel, Channel: channel,
@ -196,7 +203,7 @@ func (r *MidiRouter) sendRequest(channel, note, velocity uint8) {
r.Log(ErrorLog, "Json Encode: %s", err) r.Log(ErrorLog, "Json Encode: %s", err)
} else { } else {
r.MqttClient.Publish(trig.MqttTopic, 0, true, data) r.MqttClient.Publish(trig.MqttTopic, 0, true, data)
r.Log(SendLog, "-> [MQTT] %s", trig.MqttTopic) r.Log(SendLog, "-> [MQTT] %s: %s", trig.MqttTopic, string(data))
} }
} }
} }