i installed the docker and the app has been approved just now. where should I enter the promo code block “curl”?
any CMD window
ok i managed to send the instruction and it seems to have worked correctly. Now I have to create the docker. where should I enter the code below? there is no CMD inside the docker
docker run \
-e CLIENTID='your id' \
-e CLIENTSECRET='your secret' \
-e LOCKID='your lock id' \
-e USER='your prefixed application user' \
-e PASSWORD='your application users password md5 hashed' \
-p 5000:5000 stevendodd/ttlock
Run it in a CMD window on the machine you installed docker on
Rooot.999. I’d buy you a coffee for this integration!!!
I have written it but I am using APIs and need to re-factor to use objects before they will accept it into the main branch core/homeassistant/components/ttlock at Add-TTLock-Platform · stevendodd/core · GitHub
# Example configuration.yaml entry
lock:
- platform: ttlock
name: "New Lock"
client_id: xxx
client_secret: xxx
lockId: xxx
username: xxx
password: xxx
This lib already exists: https://github.com/tonyldo/ttlockio
And the author has also published a HA integration https://github.com/tonyldo/lock.ttlock
The library looks like I could use it but I can’t get it to authenticate atm
Here is what it looks like in my dev environment
way above my pay grade…can’t wait til it gets its “auto install” certification…thanks Steve
I approved your pull request! tks for colaborating!
any updated help for this newbie???
s
bump please?
Happy to find this topic, I hope the integration can be developed since many chinese affordable locks use ttlock an the other workwarounds didn’t work in my case.
Totally agree with you Henry_Ceron
. Fingers crossed that this gets some attention.
This worked for me, but since I wanted to run the container inside my raspberrypi I rebuilt the docker file for ARM archs and pushed it to my docker hub, if anyone wants to use it: Docker Hub
Thank you @stevendodd and all folks sharing their templates and knowledge.
I’m a newbie and would appreciate a tutorial to integrate my TTLOCK with Home Assistant.
How can I help here - I’ve been playing with both the lib and direct APIs.
What do you mean by needing to re-factor the code - is there a link to what the hassio core wants?
The barrier to deliver a home assistant integration is quite high; I have set up a working version however they won’t accept an integration that has direct API calls in the home Assistant repository; GitHub - stevendodd/core at Add-TTLock-Platform
Have a working version using GitHub - tonyldo/ttlockio: Python wrapper for TTLock API however I’m not really happy with it; in order to initiate a pull request to the core home assistant repository it probably needs a bit more effort including documentation.
"""Support for TTLock."""
from __future__ import annotations
from ttlockwrapper import TTLock, TTlockAPIError
from datetime import datetime
import time
from typing import Any
import requests
import voluptuous as vol
from homeassistant.components.lock import PLATFORM_SCHEMA, LockEntity
from homeassistant.const import (
ATTR_BATTERY_LEVEL,
ATTR_HW_VERSION,
ATTR_LOCKED,
ATTR_MODEL,
ATTR_SW_VERSION,
CONF_CLIENT_ID,
CONF_CLIENT_SECRET,
CONF_DOMAIN,
CONF_NAME,
CONF_PASSWORD,
CONF_USERNAME,
)
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
ATTR_AUTO_LOCK_TIME = "autoLockTime"
ATTR_PASSAGE_MODE = "passageMode"
ATTR_PASSAGE_MODE_AUTO_UNLOCK = "passageModeAutoUnlock"
ATTR_SOUND_VOLUME = "soundVolume"
ATTR_TAMPER_ALERT = "tamperAlert"
ATTR_ACCESS_TOKEN = "accessToken"
ATTR_ACCESS_TOKEN_EXPIRY_TIME = "accessTokenExpiryTime"
ATTR_LAST_USER = "lastUser"
ATTR_LAST_ENTRY_TIME = "lastEntryTime"
CONF_LOCK_ID = "lockId"
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Optional(CONF_DOMAIN, default="euapi.ttlock.com"): cv.string,
vol.Optional(CONF_NAME, default="TTLock"): cv.string,
vol.Required(CONF_LOCK_ID): cv.string,
vol.Required(CONF_CLIENT_ID): cv.string,
vol.Required(CONF_CLIENT_SECRET): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
}
)
def current_milli_time():
"""Return time millis."""
return round(time.time() * 1000)
def setup_platform(
hass: HomeAssistant,
config: ConfigType,
add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up the TTLock platform."""
domain = config.get(CONF_DOMAIN)
client_id = config.get(CONF_CLIENT_ID)
client_secret = config.get(CONF_CLIENT_SECRET)
user = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
lock_id = config.get(CONF_LOCK_ID)
name = config.get(CONF_NAME)
token = TTLock.get_token(client_id, client_secret, user, password, "", True)
access_token = token["access_token"]
refresh_token = token["refresh_token"]
token_expiry_time = token["expires_in"] * 1000 + current_milli_time() - 25000
add_entities(
[
TTLockDevice(
access_token,
refresh_token,
token_expiry_time,
domain,
client_id,
client_secret,
lock_id,
name,
)
],
update_before_add=True,
)
class TTLockDevice(LockEntity):
"""Representation of a TTLock device."""
def __init__(
self,
access_token,
refresh_token,
token_expiry_time,
domain,
client_id,
client_secret,
lock_id,
name,
) -> None:
"""Initialize the TTLock device."""
self._ttlock = TTLock(client_id, access_token)
self._access_token = access_token
self._refresh_token = refresh_token
self._access_token_expiry_time = token_expiry_time
self._domain = domain
self._client_id = client_id
self._client_secret = client_secret
self._lock_id = lock_id
self._nickname = name
self._auto_lock_time = -1
self._electric_quantity = -1
self._firmware_revision: str | None = None
self._hardware_revision: str | None = None
self._lock_alias: str | None = None
self._model_num: str | None = None
self._passage_mode = -1
self._passage_mode_auto_unlock = -1
self._sound_volume = -1
self._tamper_alert = -1
self._last_user = ""
self._last_entry_time: str | None = None
self._is_locked = True
self._responsive = False
@property
def name(self) -> str | None:
"""Return the name of the device."""
return self._nickname
@property
def available(self) -> bool:
"""Return True if entity is available."""
return self._responsive
@property
def is_locked(self) -> bool:
"""Return True if the device is currently locked, else False."""
return self._is_locked
def get_token(self) -> None:
"""Refresh access token."""
if current_milli_time() > self._access_token_expiry_time:
token = self._ttlock.refresh_token(
self._client_id, self._client_secret, self._refresh_token, ""
)
self._access_token = token["access_token"]
self._refresh_token = token["refresh_token"]
self._access_token_expiry_time = (
token["expires_in"] * 1000 + current_milli_time() - 25000
)
def unlock(self, **kwargs: Any) -> None:
"""Unlock the device."""
self.get_token()
self._ttlock.unlock(self._lock_id)
self._is_locked = self._ttlock.lock_state(self._lock_id)
def lock(self, **kwargs: Any) -> None:
"""Lock the device."""
self.get_token()
self._ttlock.lock(self._lock_id)
self._is_locked = self._ttlock.lock_state(self._lock_id)
def update(self) -> None:
"""Update the internal state of the device."""
try:
self._electric_quantity = self._ttlock.lock_electric_quantity(self._lock_id)
if self._ttlock.lock_state(self._lock_id) == 0:
self._is_locked = True
else:
self._is_locked = False
for user_record in self._ttlock.get_lock_records_generator(
self._lock_id, 1
):
self._last_user = user_record["username"]
self._last_entry_time = datetime.fromtimestamp(
int(user_record["lockDate"]) / 1000
).strftime("%a, %d %b %Y %H:%M")
break
self._responsive = True
except TTlockAPIError:
self._responsive = False
raise
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes."""
return {
ATTR_MODEL: self._model_num,
ATTR_SW_VERSION: self._firmware_revision,
ATTR_HW_VERSION: self._hardware_revision,
ATTR_LOCKED: self._is_locked,
ATTR_AUTO_LOCK_TIME: self._auto_lock_time,
ATTR_PASSAGE_MODE: self._passage_mode,
ATTR_PASSAGE_MODE_AUTO_UNLOCK: self._passage_mode_auto_unlock,
ATTR_SOUND_VOLUME: self._sound_volume,
ATTR_TAMPER_ALERT: self._tamper_alert,
CONF_LOCK_ID: self._lock_id,
ATTR_BATTERY_LEVEL: self._electric_quantity,
ATTR_LAST_USER: self._last_user,
ATTR_LAST_ENTRY_TIME: self._last_entry_time,
}
Is the TTLock2MQTT for this reason?
Or is it just me?
I left a GitHub issue last month.
Can you please confirm if this is an issue or just me?
I am running home assistant supervised.
Finally got everything working using TTlock2MQTT
My issue was I was using EMQX for MQTT rather than Mosquitto.
Even though that should not cause any issues but it does. For some reason, it only works with mosquito.
One crucial step missing after installing TTLOCK2MQTT is adding it to the dashboard.
It seems obvious, but some people might be struggling with that.
After installing the addon and proper connection, restart Home Assistant.
And then, you will see your TTLock gateway and lock in the MQTT as entities.
After that, we should now be able to add the lock to our UI. Go to Overview (or your choice of the dashboard) > click ‘+’ on the bottom right > click ‘By Entity’ up top > search “lock”. You should see your lock. Check all entities matching lock. Add to UI.
Finally:
How did you get this working? I’ve done everything in tonyldo-hassio-addons/DOCS.md at 183528083ba1e3d017ac97591a40a50ccf0e75cd · tonyldo/tonyldo-hassio-addons · GitHub and GitHub - tonyldo/ttlockio: Python wrapper for TTLock API but still can’t get it working.
In HASS the add-on logs show an invalid token error, but I’m absolutely certain it’s correct as I copied it directly from the https://euopen.ttlock.com/manager page
UPDATE: I got it all working at last.
Tried TTlock2MQTT today, Quite complicated to set up but I got it working. However It doesn’t not as good as I wish.
- Lock status takes a long time to update in HA starting from 1-60 sec. Even I configure publishstatdelay to 1 sec.
- When TTlock2MQTT add-on is running there are some problems with the lock. Sometimes If I press a lock from a button or App. It will lock and follow by unlocking immediately after that.