Алиса и Диммер

Прикрутил Алису к WB по инструкции с гитхаба. Поднял у себя на внешнем серваке контейнер с Yandex2Mqtt. Все хорошо, все работает. Вернее не так, работае:

  • Включение/отключение света
  • установка заданной яркости (например, “включи свет в зале на 20%”)
  • Опрос состояния (“Алиса, что со светом?”)
  • Работают сценарии…

На текущий момент не победил одну вещь: “Алиса, прибавь свет в …”
На это сообщение, алиса посылает +10 (этот параметр можно задать), y2mqtt транслирует это в 10, т.е. яркость становится 10%. Если попросить убавить, яркость будет 100%, т.к. приходит -10, а это 65535-10=65525 - максимальная яркость

Как победить, пока мыслей нет.

Вот пример устройства:

{
  "id": "dim_3",
  "name": "Над столом",
  "room": "Кухня",
  "type": "devices.types.light",
  "allowedUsers": [
    "8"
  ],
  "mqtt": [
    {
      "instance": "brightness",
      "set":   "/devices/wb-mdm3/controls/Channel 2/on",
      "state": "/devices/wb-mdm3/controls/Channel 2/on"
    },
    {
      "instance": "on",
      "set":   "/devices/wb-mdm3/controls/K2/on",
      "state": "/devices/wb-mdm3/controls/K2/on"
    }
  ],
  "valueMapping": [
    {
      "type": "on_off",
      "mapping": [[false, true], [0, 1]]
    }
  ],
  "capabilities": [
    {
      "type": "devices.capabilities.range",
      "retrievable": true,
      "parameters": {
        "instance": "brightness",
        "unit": "unit.percent",
        "random_access": true,
        "range": {
          "min": 1,
          "max": 100
        }
      }
    },
    {
      "type": "devices.capabilities.on_off",
      "retrievable": true
    }
  ]
}

Добрый, да yandex2mqtt оригинальный (GitHub - munrexio/yandex2mqtt: Bridge from Yandex Smart Home to MQTT) и самый популярный его форки (GitHub - lasthead0/yandex2mqtt: Bridge from Yandex Smart Home to MQTT) , действительно некорректно отрабатывают. Я допиливал. Потом перешел на другой форк (GitHub - petrows/yandex2mqtt: Bridge from Yandex Smart Home to MQTT) - там этот вопрос решен сразу. Но конфиги немного переписать придется.

Да, я его тоже поднимал, сейчас именно он и установлен. Переписывание конфига - это по сути его разделение на 2е части, как я понял.
В общем, здесь тоже что-то не работает. В первом посте, конфиг как раз для этого репозитория.
Может быть надо что-то еще сделать. У Вас есть пример, как связать WB-MDM3 и команду Алисы “Прибавь/убавь яркость”?

Добрый день!
Проблема в том, что при командах типа «Алиса, прибавь свет…», система воспринимает передаваемые значения как абсолютные, а не как изменения относительно текущего уровня яркости. Чтобы это исправить, необходимо настроить обработку входящих команд так, чтобы они корректно увеличивали или уменьшали текущий уровень яркости на заданную величину. Это достигается путем добавления функции, которая при получении относительных значений будет вычислять новое значение яркости на основе текущего.
Примерно такая функция должна быть.

{
  "instance": "brightness",
  "set": "/devices/wb-mdm3/controls/Channel 2/on",
  "state": "/devices/wb-mdm3/controls/Channel 2/on",
  "converter": "function(value) {
      // Получаем текущее значение яркости
      var currentBrightness = parseInt($globalStore.get('dim_3_brightness')) || 0;
      // Вычисляем новое значение яркости с учетом относительного изменения
      var newValue = currentBrightness + value;
      // Ограничиваем диапазон от 1 до 100
      if (newValue > 100) newValue = 100;
      if (newValue < 1) newValue = 1;
      // Сохраняем новое значение яркости в глобальном хранилище
      $globalStore.set('dim_3_brightness', newValue);
      return newValue;
  }"

Вот конфиг для диммера , сравнил с вашим - вы state неправильно берете

    {
            id: '1-5-1-1-dim',
            name: 'Свет над столом',
            room: 'Кабинет',
            type: 'devices.types.light',
            allowedUsers: ['1','2'],
            mqtt: [
                {
                    instance: 'on',
                    set: '/devices/wb-mdm3_50/controls/K1/on',
                    state: '/devices/wb-mdm3_50/controls/K1',
                },
                 {
                    instance: 'brightness',
                    set: '/devices/wb-mdm3_50/controls/Channel 1/on',
                    state: '/devices/wb-mdm3_50/controls/Channel 1',
                },
           ],
            valueMapping: [
                {
                    type: 'on_off',
                    mapping: [[false, true], [0, 1]], // [yandex, mqtt]
                },
            ],
            capabilities: [
                {
                    type: 'devices.capabilities.on_off',
                    retrievable: true,
                },
                {
                    type: 'devices.capabilities.range',
                    retrievable: true,

                    parameters: {
                        instance: 'brightness',
			random_access: true,
                        unit: 'unit.percent',
                        range: {
                            min: 1,
                            max: 100,
                            precision: 1
                        }
                    },
                },
		
              ],
        },

Перепроверил - для указанного форка это не нужно, там обрабатываеются относительные значения.

Я допиливал 2 функции в device.js

  1. getMappedValue для того чтобы можно было делать маппинг для разных instance одного type разный, например вот для кондиционеров
Спойлер
           valueMapping: [
                {
                    type: 'on_off',
                    mapping: [[false, true], [0, 1]], // [yandex, mqtt]
                },
                {
                    type: 'toggle',
                    mapping: [[false, true], [0, 1]], // [yandex, mqtt]
                },
                {
                    type: 'mode',
		    instance:"fan_speed",
                    mapping: [["auto", "turbo", "high", "medium", "low", "quiet"], ["0", "5", "4", "3", "2", "1"]], // [yandex, mqtt]
                },
                {
                    type: 'mode',
		    instance:"thermostat",
                    mapping: [["auto", "cool", "heat", "fan_only", "dry"], ["3", "2", "1", "5", "4"]], // [yandex, mqtt]
                },
                {
                    type: 'mode',
		    instance:"swing",
                    mapping: [["stationary", "auto", "one", "two", "three","four","five"], ["0", "1", "2", "3", "4", "5", "6"]], // [yandex, mqtt]
                },

вот изменненная функция

Спойлер
  getMappedValue(val, actType, instance, y2m) {
	//evs 010524 
        //-const map = this.data.custom_data.valueMapping.find(m => m.type == actType);
	//+
	let map;
        if (instance != undefined) {
		map = this.data.custom_data.valueMapping.find(m => m.type == actType && m.instance == instance);
	}
	
	if (map == undefined) {
		map = this.data.custom_data.valueMapping.find(m => m.type == actType);
	}
        //evs

        if (map == undefined) return val;

        // Percent invert
        if (map.mapping == 'invert_percent') {
            return 100 - parseInt(val)
        }

        // Custom function?
        if (map.mapping instanceof Function) {
            return map.mapping(this, instance, val, y2m)
        }

        var from, to;
        if (y2m == true) [from, to] = map.mapping;
        else [to, from] = map.mapping;

        const mappedValue = to[from.indexOf(val)];
        return (mappedValue != undefined) ? mappedValue : val;
    }

и функцию setCapabilitiesState, для разных значений в разных топиках, но у упор не помню для чего :slight_smile:

Спойлер
    setCapabilityState(val, relative, type, instance) {
        const {id} = this.data;
        const actType = String(type).split('.')[2];
        const value = this.getMappedValue(val, actType, instance, true);

        let relativePrefix = (relative && value > 0 && !isNaN(value)) ? '+' : ''

        let message;
        let topic, topicRaw;  //evs
        try {
            const capability = this.findCapability(type, instance);
            if (capability == undefined) throw new Error(`Can't find capability '${type}' in device '${id}'`);
            capability.state.value = val;
            //evs --
            //- topic = this.findTopicByInstance(instance);
            //- if (topic == undefined) throw new Error(`Can't find set topic for '${type}' in device '${id}'`);
	    //evs ++ //different topics for different values
	    topicRaw = this.findTopicByInstance(instance);
            if (topicRaw == undefined) throw new Error(`Can't find set topic for '${type}' in device '${id}'`);
	    logger.info(`topicRaw ${JSON.stringify(topicRaw)}`);  //evs

	    if (typeof topicRaw  == 'string') {
			topic=topicRaw;
	    } else if (typeof topicRaw  == 'object') {
		   topic = topicRaw[val];
                   if (topic == undefined) throw new Error(`Can't find set topic for value '${val}' for '${type}' in device '${id}'`);
		   } else throw new Error(`Can't find set topic (unexpected type) for '${type}' in device '${id}'`);
        //evs++
            message = `${relativePrefix}${value}`;
   
        } catch(e) {
            topic = false;
            logger.log('error', {message: `${e}`});
        }

        if (topic) {
            global.mqttClient.publish(topic, message);
        }

        logger.info(`Command ${id}: instance ${instance}, topic ${topic}, command ${val}, message ${message}`)

        return {
            type,
            'state': {
                instance,
                'action_result': {
                    'status': 'DONE'
                }
            }
        }
    }

Ого сколько всего! Спасибо! В выходные доберусь до компа и буду вникать. По результату отпишусь :wink:

Добрый день, удалось ли решить вопрос?

В общем, не получилось решить этот вопрос всеми описанными методами. Ни один форк не переводит относительные в абсолютные значения. В итоге, форкнул себе, поправил несколько моментов, касаемых “относительности” данных, разделил конфиг на отдельные подконфиги для каждого устройства (можно делать в одном конфиге, а можно делить - кому как удобнее), добавил сборку docker образа, сделал Helm Chart… Осталось дополнить документацию.
Если кому интересно: GitHub - markovna76/yandex2mqtt: Bridge from Yandex Smart Home to MQTT

ЗЫЖ

  • Вылазит какая-то ошибка в логах, но, честно, не нашел откуда берется - на работу не влияет )…
  • Ну и не программист я особо, так что за качество кода не сильно пинайте :wink:

Всем спасибо за участие в обсуждении и Ваши комментарии.

Да, кстати, еще нашел и прикрутил себе (пока в тестовом виде) сборщик данных из mqtt в prometheus и отображение их в grafana

1 лайк