volshebniks / sauresha

Integrations Saures controller to HA
MIT License
44 stars 11 forks source link

Ошибка Attempt to decode JSON with unexpected mimetype: text/html', url=URL('https://api.saures.ru/1.0/login') #53

Closed DivanX10 closed 12 months ago

DivanX10 commented 1 year ago

После обновления Home Assistant до версии 2023.9.3 перестала работать интеграция sauresha и контролер вместе с датчиками стали недоступными. Если удалить записи в интеграции и попытаться добавить по новой, то не добавляется. Логин и пароль 100% верны, так как я могу зайти с этими же данные в облачный Saures. Как исправить?

image

В логах получаю такое сообщение

Logger: custom_components.sauresha.api
Source: custom_components/sauresha/api.py:309
Integration: SauresHA ([documentation](https://github.com/volshebniks/sauresha), [issues](https://github.com/volshebniks/sauresha/issues))
First occurred: 22:16:41 (1 occurrences)
Last logged: 22:16:41

0, message='Attempt to decode JSON with unexpected mimetype: text/html', url=URL('https://api.saures.ru/1.0/login')

Home Assistant 2023.9.3 Supervisor 2023.09.2 Operating System 10.5 Пользовательский интерфейс 20230911.0 - latest

Sauresha версии 1.0.1

ewgspb commented 1 year ago

Также интеграция перестала работать , кажется после обновления HACS

Logger: custom_components.sauresha.api Source: custom_components/sauresha/api.py:95 Integration: SauresHA (documentation, issues) First occurred: 07:37:14 (1 occurrences) Last logged: 07:37:14

0, message='Attempt to decode JSON with unexpected mimetype: text/html', url=URL('https://api.saures.ru/1.0/login')

Gura73 commented 1 year ago

Подтверждаю, после обновления интеграция не работает. Обновился до: Home Assistant 2023.9.3 Supervisor 2023.09.2 Operating System 10.5 Пользовательский интерфейс 20230911.0 - latest

Logger: custom_components.sauresha.api
Source: custom_components/sauresha/api.py:309
Integration: SauresHA ([documentation](https://github.com/volshebniks/sauresha), [issues](https://github.com/volshebniks/sauresha/issues))
First occurred: 21:37:25 (1 occurrences)
Last logged: 21:37:25

0, message='Attempt to decode JSON with unexpected mimetype: text/html', url=URL('https://api.saures.ru/1.0/login')
Alfair commented 1 year ago

Подтверждаю. Хочется исправления. Если в интеграции нажать "Настроить", то не выводится номер квартиры (как раньше), а появляется красный фон ошибки. Ошибка в журнале та же что уже приводили.

volshebniks commented 1 year ago

Я смотрю ... пока не понятно. там что то в библиотеке aiohttp поменялось. Если без нее вызов API - то работает. Через неё - 403 ошибка.

Alfair commented 1 year ago

Я смотрю ... пока не понятно. там что то в библиотеке aiohttp поменялось. Если без нее вызов API - то работает. Через неё - 403 ошибка.

Я запустил пример API-вызова на Питоне (с сайта api.saures.ru/doc), там тоже используется "from aiohttp import", и этот пример работает без ошибок. У меня установлена aiohttp версии 3.8.5.

dshitikov commented 12 months ago

У меня такая же ошибка, но связана похоже с тем, что saures банит юзер агент home assistant. Если запрос уходит с юзер агентом HomeAssistant/2023.10.1 aiohttp/3.8.5 Python/3.11 - в ответ получаю html <html> <head><title>403 Forbidden</title></head> <body> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/1.25.2</center> </body> </html>,если сменить юзер агент на любой другой - все начинает работать. поправил локально пока так: auth_data = await clientsession.post( "https://api.saures.ru/1.0/login", data={"email": self._email, "password": self._password}, headers={"user-agent": "chrome"} )

DivanX10 commented 12 months ago

У меня такая же ошибка, но связана похоже с тем, что saures банит юзер агент home assistant. Если запрос уходит с юзер агентом HomeAssistant/2023.10.1 aiohttp/3.8.5 Python/3.11 - в ответ получаю html <html> <head><title>403 Forbidden</title></head> <body> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/1.25.2</center> </body> </html>,если сменить юзер агент на любой другой - все начинает работать. поправил локально пока так: auth_data = await clientsession.post( "https://api.saures.ru/1.0/login", data={"email": self._email, "password": self._password}, headers={"user-agent": "chrome"} )

Как выяснилось, теперь нужно добавить User-Agent, ранее это не указывали и работало без User-Agent, а теперь надо указать User-Agent. Можно указать User-Agent: Home Assistant и будет работать, но все же лучше указывать другое название User-Agent, которое получаем при запросе через консоль

Это рабочий код, взятый тут, но я добавил в код извлечение ID объекта, чтобы его не искать и все работало автоматом, а также добавил сенсоры, чтобы статусы сенсоров не сбрасывались после перезагрузки ХА и всегда показывали актуальные данные. Для справки, нужно ждать не менее 1 часа, когда подтянутся данные, так как в scan_interval указано 3600 (1 час), а до этого будут статусы неизвестный

#Для обеспечения равномерной нагрузки на сетевое и серверное оборудование, компания SAURES оставляет за собой право ограничивать #количество запросов в единицу времени, а также может создавать БАН листы IP адресов нарушителей. Необходимо использовать принцип #необходимого и достаточного объема обмена данными с сервером!

#В файл secrets.yaml добавить две строчки
#saures_login_payload: email=почтовый ящик&password=пароль

#Если сенсор добавили впервые, то данные подтянутся не сразу и нужно ждать указанное время в интервале. Смотрим scan_interval. #Сперва должен подтянуться SID, а после делаем HTTP запросы

#RESTful Sensor
#Документация https://www.home-assistant.io/integrations/sensor.rest
#Получаем SID. При авторизации система выдает sid, все последующие запросы выполняются передачей этого идентификатора. Cрок жизни #идентификатора 15 минут
sensor:
  - platform: rest
    name: "Saures API: SID"
    unique_id: saures api sid
    icon: mdi:package-down
    resource: https://api.saures.ru/1.0/login
    method: POST
    scan_interval: 600 #Запрос через каждые 10 минут
    timeout: 180
    headers:
      Content-Type: application/x-www-form-urlencoded; charset=utf-8
      User-Agent: HTTPie/3.2.2
    payload: !secret saures_login_payload
    value_template: "{{ value_json.data.sid }}"

#Делаем запрос objects на извлечение ID объекта. Это нужно для того, чтобы делать запросы meters, где требуется sid и id
rest:
#GET запрос objects
  - resource: https://api.saures.ru/1.0/user/objects
    scan_interval: 3600 #Запрос через каждый 1 час
    timeout: 180
    method: GET
    headers:
      User-Agent: HTTPie/3.2.2
    params:
      sid: "{{ states('sensor.saures_api_sid') }}"
    sensor:
#GET запрос ID объекта
      - name: "Saures API: GET ID Object"
        unique_id: saures api get id object
        icon: mdi:home
        value_template: >
          {% if value_json.data.objects.0.id is defined %}
            {{ value_json.data.objects.0.id }}
          {% else %}
            states('sensor.saures_api_id_object')
          {% endif %}

#GET запрос meters на извлечение заряда батарейки и показании водосчетчиков
  - resource: https://api.saures.ru/1.0/object/meters
    scan_interval: 3600 #Запрос через каждый 1 час
    timeout: 180
    method: GET
    headers:
      User-Agent: HTTPie/3.2.2
    params:
      sid: "{{ states('sensor.saures_api_sid') }}"
      id: "{{ states('sensor.saures_api_id_object') }}"
    sensor:

#GET запрос cтатуса батарейки
      - name: "Saures API: GET Controller Battery"
        unique_id: saures api get controller battery
        unit_of_measurement: "%"
        state_class: measurement
        device_class: battery
        value_template: >
          {% if value_json.data.sensors.0.bat is defined %}
            {{ value_json.data.sensors.0.bat }}
          {% else %}
            states('sensor.saures_api_get_controller_battery')
          {% endif %}

#GET запрос показания водосчетчика ГВС. Вместо xx-xxxxxx указываем SN своего счетчика
      - name: "Saures API: Water Meter Hot SNxx-xxxxxx"
        unique_id: saures api water meter hot snxx_xxxxxx
        icon: mdi:water-pump
        value_template: >
          {% for meter in value_json.data.sensors.0.meters %}
            {% if meter.sn == 'xx-xxxxxx' %}
              {{ meter.vals.0 }}
            {% endif %}
          {% endfor %}

#GET запрос показания водосчетчика ХВС. Вместо xx-xxxxxx указываем SN своего счетчика
      - name: "Saures API: Water Meter Cold SNxx-xxxxxx"
        unique_id: saures api water meter cold snxx_xxxxxx
        icon: mdi:water-pump
        value_template: >
          {% for meter in value_json.data.sensors.0.meters %}
            {% if meter.sn == 'xx-xxxxxx' %}
              {{ meter.vals.0 }}
            {% endif %}
          {% endfor %}

#Шаблоны
#https://www.home-assistant.io/integrations/template/

#После перезагрузки Home Assistant сенсоры имеют статусы unavailable, unknown. Чтобы не было таких статусов и отображались акутальные данные, будем использовать эти шаблоны

template:
#Исключаем статусы unavailable, unknown и отображаем ID объект
  - trigger:
      - platform: state
        entity_id:
          - sensor.saures_api_get_id_object
        not_to:
          - unavailable
          - unknown
    unique_id: sensor saures api get id object
    sensor:
      - name: "Saures API: ID Object"
        unique_id: sensor saures api id object
        icon: mdi:home
        state: >-
          {% if trigger.to_state.state != trigger.from_state.state %}
            {{ states('sensor.saures_api_get_id_object') }}
          {% endif %}

#Исключаем статусы unavailable, unknown и отображаем текущий уровень заряда батарейки
  - trigger:
      - platform: state
        entity_id:
          - sensor.saures_api_get_controller_battery
        not_to:
          - unavailable
          - unknown
    unique_id: sensor saures api get controller battery
    sensor:
      - name: "Saures API: Controller Battery"
        unique_id: saures api get controller battery
        icon: mdi:home
        unit_of_measurement: "%"
        state_class: measurement
        device_class: battery
        state: >-
          {% if trigger.to_state.state != trigger.from_state.state %}
            {{ states('sensor.saures_api_get_controller_battery') }}
          {% endif %}

#Исключаем статусы unavailable, unknown и отображаем актуальные показания воды для ГВС. Вместо xx-xxxxxx указываем SN своего счетчика
  - trigger:
      - platform: state
        entity_id:
          - sensor.saures_api_water_meter_hot_snxx_xxxxxx
        not_to:
          - unavailable
          - unknown
    unique_id: trigger saures api water meter hot
    sensor:
      - name: "Saures API: Water Meter Hot"
        unique_id: saures api saures water meter hot
        unit_of_measurement: m³
        state_class: total
        device_class: water
        icon: mdi:counter
        state: >-
          {% if trigger.to_state.state != trigger.from_state.state %}
            {{ states('sensor.saures_api_water_meter_hot_snxx_xxxxxx') }}
          {% endif %}

#Исключаем статусы unavailable, unknown и отображаем актуальные показания воды для ХВС. Вместо xx-xxxxxx указываем SN своего счетчика
  - trigger:
      - platform: state
        entity_id:
          - sensor.saures_api_water_meter_cold_snxx_xxxxxx
        not_to:
          - unavailable
          - unknown
    unique_id: trigger saures api water meter cold
    sensor:
      - name: "Saures API: Water Meter Cold"
        unique_id: sensor saures api water meter cold
        unit_of_measurement: m³
        state_class: total
        device_class: water
        icon: mdi:counter
        state: >-
          {% if trigger.to_state.state != trigger.from_state.state %}
            {{ states('sensor.saures_api_water_meter_cold_snxx_xxxxxx') }}
          {% endif %}

#Автоматизация
#После запуска Home Assistant будут обновлены сенсоры водосчетчиков Saures
automation:
  - alias: "Saures API: Обновить сенсоры после запуска Home Assistant"
    id: c0192c64-d64b-45b6-ab2e-91170c12f591
    trigger:
      - platform: homeassistant
        event: start
    action:
      - wait_template: "{{ has_value('sensor.saures_api_sid') }}"
      - service: homeassistant.update_entity
        target:
          entity_id: sensor.saures_api_get_controller_battery
anikin-ab commented 12 months ago

User input malformed: 10670 is not a valid option for dictionary value @ data['flats'] вот эти? [SAURES] [106] [84F3EB11**]

DivanX10 commented 12 months ago

User input malformed: 10670 is not a valid option for dictionary value @ data['flats'] вот эти? [SAURES] [106] [84F3EB11**]

id объекта верный? Чтобы проверить id объекта, откройте страницу saures api objects, где можно сгенерировать ссылку на запрос объекта и после запустить в терминале Advanced SSH & Web Terminal в Home Assistant. Выглядит это таким образом.

Сверху, это сгенерированная ссылка на запрос объекта, где в ответ, ниже видим id объекта image

Чтобы делать запросы, сперва нужно получить sid. sid можно получить после авторизации. Cрок жизни идентификатора 15 минут. Если не успеете в течение 15 минут сделать запрос, то sid будет уже недействительным. При авторизации система выдает sid, все последующие запросы выполняются передачей этого идентификатора

Установите аддон Advanced SSH & Web Terminal, зайдите в терминал и установите пакет httpie командой apt install httpie. Предварительно посмотрите не установлен ли пакет httpie командой pip show httpie, если не стоит, то устанавливаем httpie

image

Получить SID можно двумя способами

Вариант 1. Получить sid через запрос в терминале. Заходим на сайт Saures API для генерации ссылки на авторизацию, смотреть здесь. Вставляете свою почту и пароль, генерируете ссылку на авторизацию, копируете ссылку и вставляете в терминал аддона Advanced SSH & Web Terminal (обратите внимание на кавычки, читать ниже), в ответ получите sid

Если будете использовать двойные кавычки, то терминал Advanced SSH & Web Terminal будет сообщать, что "Неправильный email или пароль".

image

Вот так должен выглядеть запрос с одинарными кавычками, тогда вы получите ответ

http --form POST https://api.saures.ru/1.0/login email='почта' password='пароль'

image

Вариант 2. Создать RESTful сенсор, код ниже, где !secret saures_login_payload в секрете должны быть логин и пароль такого вида saures_login_payload: email=почтовый ящик&password=пароль

sensor:
  - platform: rest
    name: "Saures API: SID"
    unique_id: saures api sid
    icon: mdi:package-down
    resource: https://api.saures.ru/1.0/login
    method: POST
    scan_interval: 600 #Запрос через каждые 10 минут. SID будет всегда актуальный
    timeout: 180
    headers:
      Content-Type: application/x-www-form-urlencoded; charset=utf-8
      User-Agent: HTTPie/3.2.2
    payload: !secret saures_login_payload
    value_template: "{{ value_json.data.sid }}"
DivanX10 commented 12 months ago

@volshebniks Спасибо. Работает

anikin-ab commented 12 months ago

подскажите, плиз, как правильно загрузить обновление? в интеграциях он не обновляется

volshebniks commented 12 months ago

подскажите, плиз, как правильно загрузить обновление? в интеграциях он не обновляется

отображается, если подключить пользовательский репозиторий - https://github.com/volshebniks/sauresha

DivanX10 commented 12 months ago

подскажите, плиз, как правильно загрузить обновление? в интеграциях он не обновляется

отображается, если подключить пользовательский репозиторий - https://github.com/volshebniks/sauresha

Вы в manifest.json, начиная с версии 1.0.1 не указываете актуальную версию, отсюда в HACS не видит обновленную версию и не обновляется автоматически, приходится вручную переустанавливать интеграцию

image

volshebniks commented 12 months ago

видит - так HACS берет просто последнюю версию из релизов. и не важно какая там нумерация.

DivanX10 commented 12 months ago

видит - так HACS берет просто последнюю версию из релизов. и не важно какая там нумерация.

У меня долго не прилетало обновление как и у других, пришлось принудительно переустанавливать интеграцию через HACS, нажав скачать повторно.

image

Посмотрите релизы у Yandex Station и Yandex Smart Home

Они во всех релизах в манифесте указывают версию и обновление в HACS проходит автоматически

{
  "domain": "yandex_smart_home",
  "name": "Yandex Smart Home",
  "config_flow": true,
  "documentation": "https://docs.yaha-cloud.ru/v0.6.x/",
  "issue_tracker": "https://github.com/dext0r/yandex_smart_home/issues",
  "requirements": [],
  "iot_class": "cloud_polling",
  "dependencies": ["http"],
  "codeowners": ["@dext0r"],
  "version": "0.6.4"
}
{
  "domain": "yandex_station",
  "name": "Yandex.Station",
  "codeowners": [
    "@AlexxIT"
  ],
  "config_flow": true,
  "dependencies": [
    "http",
    "zeroconf"
  ],
  "documentation": "https://github.com/AlexxIT/YandexStation",
  "iot_class": "local_push",
  "issue_tracker": "https://github.com/AlexxIT/YandexStation/issues",
  "requirements": [],
  "version": "3.12.4"
}
anikin-ab commented 12 months ago

видит - так HACS берет просто последнюю версию из релизов. и не важно какая там нумерация.

нажал, только после этого появилась возможность обновления. СПАСИБО!

anikin-ab commented 11 months ago

привет. сделал обновление, перезагрузил. один раз он прогрузил счетчики воды и всё. счетчик э/э не грузил и не грузит. что-то не так..

Logger: custom_components.sauresha.api Source: custom_components/sauresha/api.py:326 Integration: SauresHA (documentation, issues) First occurred: 11 октября 2023 г. в 23:56:07 (22 occurrences) Last logged: 11:16:07

[Errno 104] Connection reset by peer

ewgspb commented 11 months ago

привет. сделал обновление, перезагрузил. один раз он прогрузил счетчики воды и всё. счетчик э/э не грузил и не грузит. что-то не так..

Logger: custom_components.sauresha.api Source: custom_components/sauresha/api.py:326 Integration: SauresHA (documentation, issues) First occurred: 11 октября 2023 г. в 23:56:07 (22 occurrences) Last logged: 11:16:07

[Errno 104] Connection reset by peer

Такая же ошибка

anikin-ab commented 11 months ago

за неделю только 2 раза обновились данные по воде по электричеству - ничего

volshebniks commented 11 months ago

к сожалению быстро разобраться в проблеме я сейчас не могу по следующим причинам

  1. я сам больше не пользуюсь устройством, а на тестовом аккаунте всё работает
  2. очень сложный период на основной работе

так что если кто то сможет разобраться в чем дело. я буду только ЗА. сам я смогу вернуться к проблеме недели через 2 только