rytilahti / python-miio

Python library & console tool for controlling Xiaomi smart appliances
https://python-miio.readthedocs.io
GNU General Public License v3.0
3.73k stars 558 forks source link

Integration in home assistant #4

Closed TribuneX closed 7 years ago

TribuneX commented 7 years ago

Hi,

does someone plan to integrate this into home assistant?

rytilahti commented 7 years ago

A very basic support is already available in this repository, I have avoided submitting it yet as I have felt the library has not received enough testing (e.g. the problem described in #1 is just fixed since yesterday.

TribuneX commented 7 years ago

Ah sorry! I just saw the documentation on it. Can you add some lines on what is currently possible via home assistant? E.g. start the robot in an action? This would help to decide if I should go through the install and test it 😃

rytilahti commented 7 years ago

It's currently a switch component, which can be used to start vacuuming (turning on) and stopping and going back to charger (turning off). Besides that it can display some information about the state of the vacuum, I haven't found out a nice way to allow controlling the fanspeed yet.

image

xavV commented 7 years ago

Hi rytilahti,

Many thanks for all your great work.. I just started to integrate the Xiaomi Mi Air Purifier and wifi mi plug into HASS (there). It works perfectly with one device, but as soon as I put 2 (air purifier + wifi plug), it leads to a checksum error:

got error when receiving: wrong checksum, read b'ffffffffffffffffffffffffffffffff', computed b'd244a4aeb1074936b12dcac897c0799f'

Do you have any idea what is happening there??

My config is as folow: switch:

Traceback (most recent call last): File "/usr/lib/python3.4/asyncio/tasks.py", line 233, in _step result = coro.throw(exc) File "/usr/local/lib/python3.4/dist-packages/homeassistant/core.py", line 1014, in _event_to_service_call yield from service_handler.func(service_call) File "/usr/local/lib/python3.4/dist-packages/homeassistant/components/switch/init.py", line 108, in async_handle_switch_service yield from switch.async_turn_off() File "/usr/lib/python3.4/asyncio/futures.py", line 388, in iter yield self # This tells Task to wait for completion. File "/usr/lib/python3.4/asyncio/tasks.py", line 286, in _wakeup value = future.result() File "/usr/lib/python3.4/asyncio/futures.py", line 277, in result raise self._exception File "/usr/lib/python3.4/concurrent/futures/thread.py", line 54, in run result = self.fn(*self.args, self.kwargs) File "/home/pi/.homeassistant/custom_components/switch/xiaomi.py", line 89, in turn_off File "/usr/local/lib/python3.4/dist-packages/xiaomi/xiaomi.py", line 142, in stop return self.send("set_power", ["off"]) File "/usr/local/lib/python3.4/dist-packages/xiaomi/xiaomi.py", line 127, in send m = Message.parse(data) File "/usr/local/lib/python3.4/dist-packages/construct/core.py", line 165, in parse return self.parse_stream(BytesIO(data), context, kw) File "/usr/local/lib/python3.4/dist-packages/construct/core.py", line 176, in parse_stream return self._parse(stream, context, "parsing") File "/usr/local/lib/python3.4/dist-packages/construct/core.py", line 849, in _parse subobj = sc._parse(stream, context, path) File "/usr/local/lib/python3.4/dist-packages/construct/core.py", line 2709, in _parse raise e.class("%s\n %s" % (e, path)) construct.core.ChecksumError: wrong checksum, read b'ffffffffffffffffffffffffffffffff', computed b'2075dd492010d77ea224728458a0a06a' parsing -> checksum

xavV commented 7 years ago

Just created a topic on homeassistant as I think it's mainly related to it.

rytilahti commented 7 years ago

I'd seriously appreciate if you'd be willing to try to get your changes included to this repository instead of creating a fork to maintain..

Now that being said, I think it may indeed be an issue how homeassistant handles the config files. The common way is to pass a list inside the same platform definition and then loop over it to create the linked devices, see e.g. https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/light/yeelight.py#L81 .

xavV commented 7 years ago

Sorry for your first point Rytilahti, I'm quite new to Github. I will make a fork of your repo and include those changes. In the meantime I found out a work around: resend the token to Utils each time we send a request. In that case I can control multiple devices.

rytilahti commented 7 years ago

Ok, not a problem. And yeah, the token handling in the library is currently awfully done, good to hear that you got it working though!

flyguy729 commented 7 years ago

Hi.

I am really new to HA, hassbian and programming in general. I manage to install xavV plugin to work with my smart plug.

However, i have 2 xiaomi components right now. One is in custom component ( which is xavV's version of yours) and the beta xiaomi integration for the smart home gateway.

In my config file, when i place the config under Switch, HA doesnt load. I have to remove the line for HA to load.

Is the file conflicting with each other? as both custom_component and component has xiaomi.py under Switch. If yes, how do i install this the proper way?

Thank you in advance.

jcastro commented 7 years ago

I have been using this on HA for a few weeks now and it works very nice, you should submit it!

I'm getting this on my log when I restart HA but still works perfectly!

2017-05-27 22:02:21 ERROR (<concurrent.futures.thread.ThreadPoolExecutor object at 0x2ad41a109dd8>_1) [mirobo.vacuum] got error when receiving: timed out

2017-05-27 22:02:21 ERROR (<concurrent.futures.thread.ThreadPoolExecutor object at 0x2ad41a109dd8>_1) [custom_components.switch.mirobo] Got exception while fetching the state: timed out

Thanks a lot for creating this!

lv-88 commented 7 years ago

@jcastro I'm getting the same errors in my HA log, although up until now it's been working, I have a automation to start the mi robot later today so I'll see for sure if it still responds, this is pretty cool!

Also agree on that this should be submitted :)

UltraSub commented 7 years ago

Not seeing the error mentioned here, running it in HA for 3 weeks now. Only thing I'm seeing is that the bot turns on if the boolean is switched to on, and then the boolean immediately switches back to off. After some time HA sees it is on and reflects the correct state.

You should seriously consider to create a PR on HA for this component, as it works flawlessly. Thanks for your work!

lv-88 commented 7 years ago

I have tested this for a few days now and it works great (despite the errors/warning in the log as mentioned above) being part of HA and my automations there! Thanks again for this! Just awesome!

mirobo_scrn

jcastro commented 7 years ago

nice one!. I got mine automated so when no one is at home it turns on. Then when someone arrives it turns off

Regularj commented 7 years ago

@xavV : Where to put your files? I just renamed your xiaomi.py to xiaomy.plug.py (because as @flyguy729 I too have already the Gateway as xiaomi.py integrated) and put it under custom_components. Anything more? Because I only get the following error:

ERROR (Thread-3) [custom_components.switch.xiaomi.plug] Got exception while fetching the state: cannot import name 'Device'

Any ideas? +1 on @jcastro. I'd love to see it being integrated into HomeAssistant

UltraSub commented 7 years ago

@lv-88 Cool, do you have the automations for the scheduler somewhere on github by any chance? I already created template sensors for everything except the scheduler. The scheduling would be the finishing touch :)

santirguez commented 7 years ago

Hi all, I am trying to use it in HASS 0.46 and I get the following error: ERROR (Thread-5) [custom_components.switch.mirobo] Got exception while fetching the state: must be str, not int Any idea where the issue can be?

Thank you!

rytilahti commented 7 years ago

@jcastro the error happens sometimes when the robot doesn't answer. Maybe the component could do a retry if it fails to receive a response, but this is not a priority at the moment.

@UltraSub the toggling issue sounds like something that could be avoided by setting the is_on in the component after a successful start.

@UltraSub, @jcastro, I haven't yet submitted it to homeassistant because lack of polishing (that error, maybe a custom card for vacuums in general like @lv-88 had done?) and the fact that it'd require writing some documentation about how to fetch the token and how to use it. It's on my todo list though.

@santirguez could you modify the line containing the error by adding exc_info=True (_LOGGER.error("Got exception while fetching the state: %s" % ex, exc_info=True) and see which line causes the error?

lv-88 commented 7 years ago

@UltraSub I don't have it up somewhere yet, the automations are really simplistic, they are based on the same concept like the Alarm Clock code on the HA forums. Works great for me! Here is one of the automations (the first one activated in the screenshot) You can tweak these to make it fit you.

  - alias: 'Mi Week (workdays)'
    trigger:
      platform: template
      value_template: '{{ states.sensor.time.state == states.sensor.mi_time.state }}'
    condition:
      - condition: time
        weekday:
          - mon
          - tue
          - wed
          - thu
          - fri
      - condition: state
        entity_id: !secret emil_device
        state: 'not_home'
    action:
      - service: homeassistant.turn_on
        entity_id:
          - switch.mi_robot_vacuum

And then the sensor templates (that use input_sliders as you can see, so create those as well and you're good to go!):

- platform: template
  sensors:
    mi_time_hour:
      value_template: '{{ states("input_slider.mi_timehour") | round(0) }}'
      friendly_name: 'Hour'
    mi_time_minutes:
      value_template: '{{ states("input_slider.mi_timeminutes") | round(0) }}'
      friendly_name: 'Minutes'
    mi_time:
      friendly_name: 'Time'
      value_template: '{{ "%0.02d:%0.02d" | format(states("input_slider.mi_timehour") | int, states("input_slider.mi_timeminutes") | int) }}'
      icon_template: mdi:clock
santirguez commented 7 years ago

Hi @rytilahti

Thank you for the hint. It was catching the token as int so i put the token in 'XXXXXXXXXX' instead of XXXXXXXXX format, and now working as a charm!

Thank you!

jcastro commented 7 years ago

@rytilahti I could help you write the documentation!

rytilahti commented 7 years ago

@jcastro I created a PR for the code part (https://github.com/home-assistant/home-assistant/pull/7913), if you want you could create a documentation here: https://github.com/home-assistant/home-assistant.github.io/tree/next/source/_components - A lot of it will be fairly similar to other components, but we need a nice explanation how one extracts the token from the robot :-)

Btw, the component is renamed to xiaomi_vacuum instead of mirobo, so when the new component gets released it requires configuration changes for those using the component currently.

Regularj commented 7 years ago

So this stays for the Xiaomi Vacuum only? Correct me if I'm wrong but didn't you want @xavV to integrate his changes to your repo so the Wifi plug and the Air Purifier work too? :-)

rytilahti commented 7 years ago

@Regularj I have nothing against integrating support for more devices but sofar I haven't received PRs. Looks like https://github.com/aholstenson/miio supports quite a few different devices with the same protocol so it'd be just about putting some effort to make it happen in python too. (It's more or less adding wrappers for different type of device communication). Only thing that doesn't (perhaps) make sense to support here is the xiaomi gateway (assuming the homeassistant support for it will be done using a separate lib), and yeelight bulbs (there's python-yeelight, which requires enabling developer mode though).

There is a PR #13 for fixing an issue with out-of-sync clocks (apparently happens with some devices), but I haven't yet had time to go and test it thoroughly.

edit: to add, adding support for more devices into homeassistant would require creating separate components I think, considering how different the devices are.

pixeye33 commented 7 years ago

Really glad to see this happening ! already testing the new component, works like a charm 👍

@jcastro nice work on documentation ! I think some users would prefer the method using packet sender ;) (not really practical to put RPI in wifi client mode, on a running home assistant)

jcastro commented 7 years ago

@pixeye33 sure! I would love to add it... can you point me in the right direction to a tutorial or something regarding the packet sender method? thanks!

pixeye33 commented 7 years ago

It's this method : https://github.com/rytilahti/python-mirobo/issues/5#issuecomment-298165119 (it says "last 16 characters", but it's 32 !)

here's what it looks like : https://cloud.githubusercontent.com/assets/1382471/26220874/ba69f44e-3c14-11e7-96e5-5e2bb4b35052.png

jcastro commented 7 years ago

@lv-88 would you mind if I add your configuration and automations as an additional config example in the documentation? If no problem, could you send me the entire update code for the automations and sensors? thanks!

lv-88 commented 7 years ago

@jcastro sure thing! Go ahead, here is everything in my current setup, I'm sure you can make it more "generic" for the documentation:

#### GROUP ####
Mi Robot Quick Control:
      - switch.mi_robot_vacuum
      - sensor.mi_info_status
      - sensor.mi_info_battery
      - sensor.mi_info_fanspeed
      - sensor.mi_info_cleanedarea
      - sensor.mi_info_cleaningtime
      - sensor.mi_info_errors

Mi Robot Scheduler:
    name: Mi Robot Scheduler
    entities:
      - sensor.mi_time
      - input_slider.mi_timehour
      - input_slider.mi_timeminutes
      - automation.mi_week_workdays
      - automation.mi_week_mon_wed_fri
      - automation.mi_weekend

#### INPUT SLIDERS ####
mi_timehour:
    name: Hour
    icon: mdi:timer
    initial: 14
    min: 0
    max: 23
    step: 1
mi_timeminutes:
    name: Minutes
    icon: mdi:timer
    initial: 00
    min: 0
    max: 55
    step: 5

#### SENSORS ####
    mi_time_hour:
      value_template: '{{ states("input_slider.mi_timehour") | round(0) }}'
      friendly_name: 'Hour'
    mi_time_minutes:
      value_template: '{{ states("input_slider.mi_timeminutes") | round(0) }}'
      friendly_name: 'Minutes'
    mi_time:
      friendly_name: 'Time'
      value_template: '{{ "%0.02d:%0.02d" | format(states("input_slider.mi_timehour") | int, states("input_slider.mi_timeminutes") | int) }}'
      icon_template: mdi:clock

#### SENSORS TO SHOW THE DIFFERENT ATTRIBUTES ####
    mi_info_status:
      value_template: '{{ states.switch.mi_robot_vacuum.attributes.Status}}'
      friendly_name: 'Status'
      icon_template: mdi:comment

    mi_info_battery:
      value_template: '{{ states.switch.mi_robot_vacuum.attributes.Battery}}'
      friendly_name: 'Battery'
      unit_of_measurement: '%'
      icon_template: mdi:battery-charging-100

    mi_info_fanspeed:
      value_template: '{{ states.switch.mi_robot_vacuum.attributes.Fan}}'
      friendly_name: 'Fanspeed'
      unit_of_measurement: '%'
      icon_template: mdi:fan

    mi_info_cleanedarea:
      value_template: '{{ states.switch.mi_robot_vacuum.attributes["Cleaned area"] | round(0) }}'
      friendly_name: 'Cleaned area'
      unit_of_measurement: 'm2'
      icon_template: mdi:map

    mi_info_cleaningtime:
      value_template: '{{ states.switch.mi_robot_vacuum.attributes["Cleaning time"]}}'
      friendly_name: 'Cleaning time'
      icon_template: mdi:clock

    mi_info_errors:
      value_template: '{{ states.switch.mi_robot_vacuum.attributes.Error}}'
      friendly_name: 'Errors'
      icon_template: mdi:alert-circle

#### AUTOMATION ####
  - alias: 'Mi Week (workdays)'
    trigger:
      platform: template
      value_template: '{{ states.sensor.time.state == states.sensor.mi_time.state }}'
    condition:
      - condition: time
        weekday:
          - mon
          - tue
          - wed
          - thu
          - fri
      - condition: state
        entity_id: !secret emil_device
        state: 'not_home'
    action:
      - service: homeassistant.turn_on
        entity_id:
          - switch.mi_robot_vacuum

  - alias: 'Mi Week (mon, wed, fri)'
    trigger:
      platform: template
      value_template: '{{ states.sensor.time.state == states.sensor.mi_time.state }}'
    condition:
      - condition: time
        weekday:
          - mon
          - wed
          - fri
      - condition: state
        entity_id: !secret emil_device
        state: 'not_home'
    action:
      - service: homeassistant.turn_on
        entity_id:
          - switch.mi_robot_vacuum

  - alias: 'Mi Weekend'
    trigger:
      platform: template
      value_template: '{{ states.sensor.time.state == states.sensor.mi_time.state }}'
    condition:
      - condition: time
        weekday:
          - sat
          - sun
      - condition: state
        entity_id: !secret emil_device
        state: 'not_home'
    action:
      - service: homeassistant.turn_on
        entity_id:
          - switch.mi_robot_vacuum
UltraSub commented 7 years ago

Seeing a lot of time-outs in hass log. Any idea where they come from or even better, how to solve it? :)

June 26th 2017, 08:11:58.000    ERROR   mirobo.vacuum   got error when receiving: timed out#033[0m
June 26th 2017, 08:11:58.000    ERROR   custom_components.switch.mirobo Got exception while fetching the state: timed out#033[0m
June 26th 2017, 08:11:58.000    ERROR   mirobo.vacuum   got error when receiving: timed out
June 26th 2017, 08:11:58.000    ERROR   custom_components.switch.mirobo Got exception while fetching the state: timed out
June 26th 2017, 07:10:46.000    ERROR   custom_components.switch.mirobo Got exception while fetching the state: timed out#033[0m
June 26th 2017, 07:10:46.000    ERROR   custom_components.switch.mirobo Got exception while fetching the state: timed out
June 26th 2017, 07:10:46.000    ERROR   mirobo.vacuum   got error when receiving: timed out#033[0m
June 26th 2017, 07:10:46.000    ERROR   mirobo.vacuum   got error when receiving: timed out
June 26th 2017, 04:49:46.000    ERROR   custom_components.switch.mirobo Got exception while fetching the state: timed out#033[0m
June 26th 2017, 04:49:46.000    ERROR   custom_components.switch.mirobo Got exception while fetching the state: timed out
June 26th 2017, 04:49:46.000    ERROR   mirobo.vacuum   got error when receiving: timed out
June 26th 2017, 04:49:46.000    ERROR   mirobo.vacuum   got error when receiving: timed out#033[0m
June 26th 2017, 04:09:38.000    ERROR   mirobo.vacuum   got error when receiving: timed out
June 26th 2017, 04:09:38.000    ERROR   mirobo.vacuum   got error when receiving: timed out#033[0m
June 26th 2017, 04:09:38.000    ERROR   custom_components.switch.mirobo Got exception while fetching the state: timed out#033[0m
June 26th 2017, 04:09:38.000    ERROR   custom_components.switch.mirobo Got exception while fetching the state: timed out
June 26th 2017, 02:23:17.000    ERROR   mirobo.vacuum   got error when receiving: timed out#033[0m
June 26th 2017, 02:23:17.000    ERROR   custom_components.switch.mirobo Got exception while fetching the state: timed out#033[0m
June 26th 2017, 02:23:17.000    ERROR   custom_components.switch.mirobo Got exception while fetching the state: timed out
June 26th 2017, 02:23:17.000    ERROR   mirobo.vacuum   got error when receiving: timed out
June 26th 2017, 02:00:42.000    ERROR   mirobo.vacuum   got error when receiving: timed out#033[0m
June 26th 2017, 02:00:42.000    ERROR   custom_components.switch.mirobo Got exception while fetching the state: timed out
June 26th 2017, 02:00:42.000    ERROR   custom_components.switch.mirobo Got exception while fetching the state: timed out#033[0m
June 26th 2017, 02:00:42.000    ERROR   mirobo.vacuum   got error when receiving: timed out
June 26th 2017, 00:58:00.000    ERROR   mirobo.vacuum   got error when receiving: timed out#033[0m
June 26th 2017, 00:58:00.000    ERROR   mirobo.vacuum   got error when receiving: timed out
rytilahti commented 7 years ago

That problem is probably related to #14 .

UltraSub commented 7 years ago

Not sure. Don't think so. Had this from day one according to Kibana. And never upgraded firmware during the last 9 weeks.

rytilahti commented 7 years ago

Sometimes the robot doesn't answer even when everything is fine, or that's my experience with older firmware versions. When I get the problem with the newest FW sorted out, maybe it'd make sense to send the command multiple times. Anyway, the timeout comes from the fact that the robot is not answering to the request.

rytilahti commented 7 years ago

This has been merged to the upstream, I'll going to bump the version after the 0.1.0 release which fixes it also for the newer firmware versions, closing this now.

TribuneX commented 7 years ago

I added the robot as a switch in home assistant. I am also seeing frequent errors in my log:

2017-07-10 23:06:06 ERROR (Thread-10) [mirobo.vacuum] got error when receiving: timed out 2017-07-10 23:06:06 ERROR (Thread-10) [custom_components.switch.xiaomi_vacuum] Got exception while fetching the state: timed out

Furthermore, the robot sometimes does not turn on, when triggered in home assistant. The log shows:

2017-07-10 23:08:02 ERROR (Thread-1) [custom_components.switch.xiaomi_vacuum] Unable to start the vacuum: timed out

I wanted to replace the timer set in the Home app with home assistant. But then the robot must reliably turn on if I it is started by an automation. Any idea?

Even mirobo status sometimes can not find the robot

(homeassistant) homeassistant@pi:/home/pi$ mirobo status ERROR:mirobo.device:Unable to discover a device at address 192.168.178.47

But even if the status command works, home assistant can`t connect to the robot. Two hours ago, everything worked without an issue.

rytilahti commented 7 years ago

@TribuneX What version of python-mirobo are you running and when did you update the the component? Are you sure this is not related to #14 ?

edit: the component is now part of homeassistant, and the version 0.1.1 is a requirement in the current dev branch. One problematic part could be that homeassistant tries to update the status of the robot quite often, potentially causing problems with sequence numbers if one tries to use mirobo console tool at the same time, I suppose.

TribuneX commented 7 years ago

I was running 0.0.9. I am just updated to 0.1.1 and will check if the issue is solved.

Will this component be included in the next HASS release which will be released on the next weekend? I am currently running it as a custom component.

TribuneX commented 7 years ago

Still get the same errors in the log with 0.1.1. My robot runs firmware version 3.3.9_003073

2017-07-12 22:16:14 ERROR (Thread-1) [custom_components.switch.xiaomi_vacuum] Got exception while fetching the state: timed out 2017-07-12 22:16:45 ERROR (Thread-12) [mirobo.vacuum] got error when receiving: timed out 2017-07-12 22:16:45 ERROR (Thread-12) [custom_components.switch.xiaomi_vacuum] Got exception while fetching the state: timed out 2017-07-12 22:17:16 ERROR (Thread-7) [mirobo.vacuum] got error when receiving: timed out 2017-07-12 22:17:16 ERROR (Thread-7) [custom_components.switch.xiaomi_vacuum] Got exception while fetching the state: timed out 2017-07-12 22:17:47 ERROR (Thread-6) [mirobo.vacuum] got error when receiving: timed out 2017-07-12 22:17:47 ERROR (Thread-6) [custom_components.switch.xiaomi_vacuum] Got exception while fetching the state: timed out 2017-07-12 22:18:18 ERROR (Thread-9) [mirobo.vacuum] got error when receiving: timed out 2017-07-12 22:18:18 ERROR (Thread-9) [custom_components.switch.xiaomi_vacuum] Got exception while fetching the state: timed out 2017-07-12 22:19:20 ERROR (Thread-4) [mirobo.vacuum] got error when receiving: timed out 2017-07-12 22:19:20 ERROR (Thread-4) [custom_components.switch.xiaomi_vacuum] Got exception while fetching the state: timed out

rytilahti commented 7 years ago

Yes, it is to be released with the next HASS release. Are you using the custom component from homeassistant repo or from this one? The time outs are reported when the device does not answer to queries for reason or another.. Are you running multiple scripts trying to connect with the device at the same time? In anycase, please create a new issue for those troubles, this task has been closed for a while as the integration is already done.

santirguez commented 7 years ago

Hi all,

Recently I am having this error, after I got it working normally:

Traceback (most recent call last):
  File "/usr/lib/python3.4/asyncio/tasks.py", line 233, in _step
    result = coro.throw(exc)
  File "/srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/helpers/entity_component.py", line 381, in async_process_entity
    new_entity, self, update_before_add=update_before_add
  File "/srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/helpers/entity_component.py", line 212, in async_add_entity
    yield from self.hass.async_add_job(entity.update)
  File "/usr/lib/python3.4/asyncio/futures.py", line 388, in __iter__
    yield self  # This tells Task to wait for completion.
  File "/usr/lib/python3.4/asyncio/tasks.py", line 286, in _wakeup
    value = future.result()
  File "/usr/lib/python3.4/asyncio/futures.py", line 277, in result
    raise self._exception
  File "/usr/lib/python3.4/concurrent/futures/thread.py", line 54, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/components/switch/xiaomi_vacuum.py", line 110, in update
    from mirobo import DeviceException
ImportError: cannot import name 'DeviceException'

I tried to uninstall and install again python-mirobo, uninstall ir completely and let HA install it automatically, but I always got the same error. If I try to import DeviceException from python console, I can do it normally. Anyone have any guess?

Thank you! Santi