Add support for Levoit Classic 300S Smart Ultrasonic Top-Fill Cool Mist Humidifier in the VeSync integration

Yup!

PR: Add humidifier device support to Vesync platform by heebnerd · Pull Request #63870 · home-assistant/core · GitHub

I believe there was one more thing - device_info for night light. Without that, this entity will be detached from device, and hang as separate entity.

It’s in light.py file. Please check, there’s if-statement for night light and separate class for it.

Hello. I followed the instructions above. I downloaded the zip and extracted it under “custom_components”. I see it there, the folder is vesync_formatbce and the permissions are identical to other components and the contents look to be ok, but after doing a server restart from the configuration panel, I only see the plain VeSync integration, not the vesync_formatbce.
Any ideas what I’m missing?

I’ll leave this post, just in case it helps someone else, but the answer was a browser restart. It just was caching the old integrations list.

Kertz1954:
Could you share the lovelace code that created the cards (that you captured in your post) in your HA configuration? It would save us all a bit of time!
paulearley

1 Like

No problem. Here’s the one for the Levoit Humidifier Classic 300S

type: vertical-stack
cards:

  • type: markdown
    content: Levoit Humidifier Classic 300S
    style: |
    ha-card
    {
    background-color: transparent;
    box-shadow: 0px 0px;
    border-top: 1px solid yellow;
    border-left: 1px solid yellow;
    border-right: 1px solid yellow;
    border-bottom: 0px solid yellow;
    border-radius: 20px 20px 0px 0px;
    color: white;
    text-align: center;
    font-size: 26px;
    line-height: 1px;
    padding-bottom: 10px;
    margin-bottom: -10px;
    }

  • type: horizontal-stack
    cards:

    • type: button
      tap_action:
      action: call-service
      service: humidifier.set_mode
      service_data:
      mode: auto
      target:
      entity_id: humidifier.humber
      icon: mdi:air-humidifier
      icon_height: 44px
      name: Auto
      entity: humidifier.humber
      show_state: false
      show_icon: true
      style: |
      :host {

      }
      ha-card
      {
      background-color: transparent;
      box-shadow: 0px 0px;
      border-top: 1px solid white;
      border-left: 1px solid yellow;
      border-right: 1px solid white;
      border-bottom: 1px solid white;

      color: {% if states("humidifier.humber") == "on" and
                                      state_attr("humidifier.humber","mode") == "auto"%}
                                      yellow  
                                      {% else %} white {% endif %};
      
      --paper-item-icon-active-color: {% if states("humidifier.humber") == "on" and  state_attr("humidifier.humber","mode") == "auto"%}
                                      yellow  
                                      {% else %} white {% endif %};
      

      }

    • type: button
      tap_action:
      action: call-service
      service: humidifier.set_mode
      service_data:
      mode: manual low
      target:
      entity_id: humidifier.humber
      icon: mdi:air-humidifier
      icon_height: 44px
      name: Low
      entity: humidifier.humber
      show_state: false
      style: |
      :host {

      }
      ha-card
      {
      background-color: transparent;
      box-shadow: 0px 0px;
      color: {% if state_attr(“humidifier.humber”,“mode”) == “manual low” and
      states(“humidifier.humber”) == “on” %}
      yellow {% else %} white {% endif %};
      border: 1px solid white;
      –paper-item-icon-active-color: {% if state_attr(“humidifier.humber”,“mode”) == “manual low” %}
      yellow {% else %} white {% endif %};
      }

    • type: button
      tap_action:
      action: call-service
      service: humidifier.set_mode
      service_data:
      mode: manual mid
      target:
      entity_id: humidifier.humber
      icon: mdi:air-humidifier
      icon_height: 44px
      name: Mid
      entity: humidifier.humber
      show_state: false
      style: |
      :host {

      }
      ha-card
      {
      background-color: transparent;
      box-shadow: 0px 0px;
      color: {% if state_attr(“humidifier.humber”,“mode”) == “manual mid” and
      states(“humidifier.humber”) == “on” %}
      yellow {% else %} white {% endif %};
      border: 1px solid white;
      –paper-item-icon-active-color: {% if state_attr(“humidifier.humber”,“mode”) == “manual mid” %}
      yellow {% else %} white {% endif %};
      }

    • type: button
      tap_action:
      action: call-service
      service: humidifier.set_mode
      service_data:
      mode: manual high
      target:
      entity_id: humidifier.humber
      icon: mdi:air-humidifier
      icon_height: 44px
      name: High
      entity: humidifier.humber
      show_state: false
      style: |
      :host {

      }
      ha-card
      {
      background-color: transparent;
      box-shadow: 0px 0px;
      color: {% if state_attr(“humidifier.humber”,“mode”) == “manual high” and
      states(“humidifier.humber”) == “on” %}
      yellow {% else %} white {% endif %};
      border: 1px solid white;
      –paper-item-icon-active-color: {% if state_attr(“humidifier.humber”,“mode”) == “manual high” %}
      yellow {% else %} white {% endif %};
      }

    • type: button
      entity: humidifier.humber
      icon: mdi:air-humidifier-off
      show_state: false
      show_icon: true
      hold_action:
      action: more-info
      icon_height: 44px
      tap_action:
      action: call-service
      service: humidifier.turn_off
      service_data: {}
      target:
      entity_id: humidifier.humber
      name: ‘Off’
      style: |
      :host {

      }
      ha-card {
      background-color: transparent;
      box-shadow: 0px 0px;
      border-top: 1px solid white;
      border-left: 1px solid white;
      border-right: 1px solid yellow;
      border-bottom: 1px solid white;

      color: {% if states("humidifier.humber") == "off" %}
                                      yellow {% else %} white {% endif %};  
      
      --secondary-text-color: {% if states('humidifier.humber') == "off" %} white                                
                               {% else %} yellow
                               {% endif %};
      
      --paper-item-icon-active-color: {% if states("humidifier.humber") == "off" %}
                                      yellow {% else %} white {% endif %};      
      
      --paper-item-icon-color: {% if states("humidifier.humber") == "off" %}
                                      yellow {% else %} white {% endif %};
      

      }

  • type: humidifier
    entity: humidifier.humber
    name: Target Humidity
    style: |
    ha-card {
    background-color: transparent;
    box-shadow: 0px 0px;
    border-top: 0px solid white;
    border-left: 1px solid yellow;
    border-right: 1px solid yellow;
    border-bottom: 0px solid white;

    color: {% if states('humidifier.humber') == "off" %} white                                
                             {% else %} yellow
                             {% endif %};
    --primary-text-color: {% if states('humidifier.humber') == "off" %} white                                
                             {% else %} yellow
                             {% endif %};
    --secondary-text-color: {% if states('humidifier.humber') == "off" %} white                                
                             {% else %} yellow
                             {% endif %};
    
    animation: blink 0s linear infinite;
    background-image: {% if states('sensor.plug_ah_milliamps') | float(default=0) != 0 and states('humidifier.humber') != "off" %}                                        
                      url("/local/images/humidifier-on.gif")
                      {% endif %};
    
    background-repeat: no-repeat;   
    background-size: 100% 100%;
      padding-top: 11px;
      margin-top: -11px;
    

    }

  • type: entities
    entities:

    • icon: mdi:air-humidifier
      name: Current Humidifier Humidity
      state: ‘{{state_attr(“humidifier.humber”,“current_humidity”)}} %’
      type: custom:template-entity-row

    • icon: mdi:air-humidifier
      name: Mode
      state: >-
      {% if state_attr(“humidifier.humber”,“mode”) == “manual low” %} Manual
      Low {% elif state_attr(“humidifier.humber”,“mode”) == “manual mid” %}
      Manual Medium {% elif state_attr(“humidifier.humber”,“mode”) ==
      “manual high” %} Manual High

      {% elif state_attr(“humidifier.humber”,“mode”) == “auto” and
      state_attr(“humidifier.humber”,“current_humidity”) <
      state_attr(“humidifier.humber”,“humidity”) and
      states(“humidifier.humber”) == “on” %} Auto {% else %} Auto
      Standby {% endif %}
      type: custom:template-entity-row

    • icon: mdi:air-humidifier
      name: Current Room Humidity
      state: ‘{{states(“sensor.bme280_humidity”)| round(default=0) }} %’
      type: custom:template-entity-row

    • icon: mdi:air-humidifier
      name: Refill Water Tank
      state: ‘{{state_attr(“humidifier.humber”,“water_lacks”)}}’
      type: custom:template-entity-row
      style: |
      :host {
      –paper-item-icon-color: white;

    }
    #states > * {
    margin: -9px 0px !important;
    }
    ha-card
    {
    background-color: transparent;
    box-shadow: 0px 0px;
    border-top: 0px solid yellow;
    border-left: 1px solid yellow;
    border-right: 1px solid yellow;
    border-bottom: 1px solid yellow;
    border-radius: 0px 0px 20px 20px;
    color: white;
    margin-top: -11px;
    }
    show_header_toggle: false

I’ve been using your custom integration for a few weeks with the Classic 300S, and everything has been working great, humidity target, mode setting, display and light. I recently got the Dual 200S (which doesn’t have a light), and when the device was added to the HA integration, the light entity of the 300S disappeared. I tried deleting and rebooting HA with no luck. I still can control target level, mode and display on/off for both devices but not the light of the 300S.
I read that there’s still issues with the night light, but is there anything else I can try to get it working again?

Hi!

Logs would help greatly to identify exact issue. But on first glance it looks like lagging of API.

1 Like

Hi! Thank you for replying so fast. Yeah after reading through this thread, it seems like it’s an API issue.
Here’s the log for the homeassistant.components.light, let me know if I can do anything else to help you with this project.

Logger: homeassistant.components.light
Source: custom_components/vesync_formatbce/light.py:50
Integration: Light (documentation, issues)
First occurred: 10:25:34 AM (1 occurrences)
Last logged: 10:25:34 AM

Error while setting up vesync_formatbce platform for light

Traceback (most recent call last): File “/usr/src/homeassistant/homeassistant/helpers/entity_platform.py”, line 249, in _async_setup_platform await asyncio.shield(task) File “/config/custom_components/vesync_formatbce/light.py”, line 40, in async_setup_entry _async_setup_entities(hass.data[DOMAIN][VS_LIGHTS], async_add_entities) File “/config/custom_components/vesync_formatbce/light.py”, line 50, in _async_setup_entities elif DEV_TYPE_TO_HA.get(dev.device_type) in (“bulb-tunable-white”): TypeError: 'in ’ requires string as left operand, not NoneType

Ok, it’s not the API.
It’s actually a bug.

I will fix it ASAP. Looks like it tries to add light for 200s.

1 Like

Awesome! Thanks!

Please try latest code and check if it works.

1 Like

Tried it, and everything is working including the night light of the 300S. I’ll report back in a week or so. Thanks again!

Perfect. Thanks for reporting!

1 Like

Still not seeing it, maybe I put it in the wrong place?

Hmm, mine is in same place.
Maybe, some errors in logs after restarting HA?

Hi, 1st of all thanks for your work
i installed ur custom component but dont show any devices…
I have a Dual 200S humidifier, whats wrong?

Captura de pantalla 2022-01-30 150932

Hello!
Could you please check HA logs related to integration?
Also, make sure that you have this device configured in VeSync application.

This is only i can see in logs

Logger: homeassistant.config_entries
Source: helpers/entity_component.py:172
First occurred: 17:49:07 (4 occurrences)
Last logged: 17:49:07

Error unloading entry *******@gmail.com for switch
Error unloading entry ********@gmail.com for fan
Error unloading entry *********@gmail.com for light
Error unloading entry *********@gmail.com for humidifier
Traceback (most recent call last):
File “/usr/src/homeassistant/homeassistant/config_entries.py”, line 466, in async_unload
result = await component.async_unload_entry(hass, self)
File “/usr/src/homeassistant/homeassistant/components/switch/init.py”, line 95, in async_unload_entry
return await component.async_unload_entry(entry)
File “/usr/src/homeassistant/homeassistant/helpers/entity_component.py”, line 172, in async_unload_entry
raise ValueError(“Config entry was never loaded!”)
ValueError: Config entry was never loaded!

I have my humidifier in the vesync App, Maybe not compatible? This is my model:

https://levoit.com/products/dual-200s-smart-top-fill-humidifier

Thanks

Logs showing, that you tried to delete integration, maybe?
Can you try to delete, restart HA and configure integration again?
Also pls make sure you have latest code.
Other that that, I can’t suggest, what’s going wrong.
There is the way to debug this on lower level: using pyvesync library on PC. If you’re getting desperate, please check it out.

I tried and nothing, only show This ok log
Logger: homeassistant.helpers.frame
Source: helpers/frame.py:103
First occurred: 18:28:19 (2 occurrences)
Last logged: 18:28:19

Detected integration that accessed discovery_info.contains(‘ssdp_location’) instead of discovery_info.upnp.contains(‘ssdp_location’) or discovery_info.ssdp_headers.contains(‘ssdp_location’); this will fail in version 2022.6. Please report issue for upnp using this method at homeassistant/components/upnp/device.py, line 78: if ssdp.ATTR_SSDP_LOCATION not in headers:
Detected integration that accessed discovery_info[‘ssdp_location’] instead of discovery_info.ssdp_location, discovery_info.upnp[‘ssdp_location’] or discovery_info.ssdp_headers[‘ssdp_location’]; this will fail in version 2022.6. Please report issue for upnp using this method at homeassistant/components/upnp/device.py, line 81: location = headers[ssdp.ATTR_SSDP_LOCATION]

Maybe not related with the humidifier.