-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Hantick
committed
Dec 30, 2024
1 parent
45fbe2b
commit 6b24c9c
Showing
17 changed files
with
925 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# Home Assistant TickTick Integration | ||
|
||
 | ||
 | ||
 | ||
|
||
Integration implements [TickTick Open API](https://developer.ticktick.com/docs#/openapi) and exposes it as a services in Home Assistant, allowing you to manage your tasks and projects programmatically 😎 | ||
|
||
## Installation | ||
|
||
1. Navigate to [TickTick Developer](https://developer.ticktick.com/manage) and click `New App` | ||
2. Name your app and set `OAuth redirect URL` to `https://my.home-assistant.io/redirect/oauth` | ||
3. Add this repository in HACS and download TickTick Integration via HACS | ||
4. Setup the integration in devices tab | ||
|
||
## Exposed Services | ||
|
||
### Task Services | ||
|
||
Get, Create, Update, Delete, Complete Task | ||
|
||
### Project Services | ||
|
||
Get (Create, Update, Delete are missing for now) | ||
|
||
## Left to be done: | ||
|
||
- Create/Update Task Service: `items` - The list of subtasks | ||
- Create/Update Task Service: `reminders` - Can create some better builder for reminders | ||
- Create/Update Task Service: `repeatFlag` - Can create some better builder for reminders | ||
- Get Project By ID Service | ||
- Get Project By ID With Data Service | ||
- Create Project | ||
- Update Project | ||
- Delete Project | ||
- Some sensors and entities creation |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,101 @@ | ||
""" | ||
Configuration: | ||
"""The TickTick Integration integration.""" | ||
|
||
To use the hello_world component you will need to add the following to your | ||
configuration.yaml file. | ||
ticktick: | ||
""" | ||
from __future__ import annotations | ||
|
||
from homeassistant.core import HomeAssistant | ||
from homeassistant.helpers.typing import ConfigType | ||
from .constants import DOMAIN | ||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.core import HomeAssistant, SupportsResponse | ||
from homeassistant.helpers import aiohttp_client, config_entry_oauth2_flow | ||
|
||
from . import api | ||
from .const import DOMAIN | ||
from .service_handlers import ( | ||
handle_complete_task, | ||
handle_create_task, | ||
handle_update_task, | ||
handle_delete_task, | ||
handle_get_projects, | ||
handle_get_task, | ||
) | ||
from .ticktick.ticktick_api import TickTickApiClient | ||
|
||
type TickTickConfigEntry = ConfigEntry[api.AsyncConfigEntryAuth] | ||
|
||
|
||
async def async_setup_entry(hass: HomeAssistant, entry: TickTickConfigEntry) -> bool: | ||
"""Set up TickTick Integration from a config entry.""" | ||
|
||
implementation = ( | ||
await config_entry_oauth2_flow.async_get_config_entry_implementation( | ||
hass, entry | ||
) | ||
) | ||
|
||
session = config_entry_oauth2_flow.OAuth2Session(hass, entry, implementation) | ||
|
||
# Using an aiohttp-based API lib | ||
entry.runtime_data = api.AsyncConfigEntryAuth( | ||
aiohttp_client.async_get_clientsession(hass), session | ||
) | ||
|
||
access_token = await entry.runtime_data.async_get_access_token() | ||
tickTickApiClient = TickTickApiClient(entry.runtime_data._websession, access_token) # noqa: SLF001 | ||
|
||
await register_services(hass, tickTickApiClient) | ||
|
||
platforms = [] # no platforms for now, change in the future TODO | ||
await hass.config_entries.async_forward_entry_setups(entry, platforms) | ||
|
||
return True | ||
|
||
|
||
async def async_unload_entry(hass: HomeAssistant, entry: TickTickConfigEntry) -> bool: | ||
"""Unload a TickTick config entry.""" | ||
return await hass.config_entries.async_unload(entry) | ||
|
||
|
||
async def register_services( | ||
hass: HomeAssistant, tickTickApiClient: TickTickApiClient | ||
) -> None: | ||
"""Register TickTick services.""" | ||
|
||
hass.services.async_register( | ||
DOMAIN, | ||
"get_task", | ||
await handle_get_task(tickTickApiClient), | ||
supports_response=SupportsResponse.OPTIONAL, | ||
) | ||
hass.services.async_register( | ||
DOMAIN, | ||
"create_task", | ||
await handle_create_task(tickTickApiClient), | ||
supports_response=SupportsResponse.OPTIONAL, | ||
) | ||
hass.services.async_register( | ||
DOMAIN, | ||
"update_task", | ||
await handle_update_task(tickTickApiClient), | ||
supports_response=SupportsResponse.OPTIONAL, | ||
) | ||
hass.services.async_register( | ||
DOMAIN, | ||
"complete_task", | ||
await handle_complete_task(tickTickApiClient), | ||
supports_response=SupportsResponse.OPTIONAL, | ||
) | ||
hass.services.async_register( | ||
DOMAIN, | ||
"delete_task", | ||
await handle_delete_task(tickTickApiClient), | ||
supports_response=SupportsResponse.OPTIONAL, | ||
) | ||
|
||
def setup(hass: HomeAssistant, config: ConfigType) -> bool: | ||
"""Setup of the TickTick integration.""" | ||
return True | ||
hass.services.async_register( | ||
DOMAIN, | ||
"get_projects", | ||
await handle_get_projects(tickTickApiClient), | ||
supports_response=SupportsResponse.OPTIONAL, | ||
) | ||
# hass.services.async_register(DOMAIN, 'get_project', await handle_my_service) | ||
# hass.services.async_register(DOMAIN, 'get_detailed_project', handle_my_service(tickTickApiClient)) | ||
# hass.services.async_register(DOMAIN, 'delete_project', handle_my_service(tickTickApiClient)) | ||
# hass.services.async_register(DOMAIN, 'create_project', handle_my_service(tickTickApiClient)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
"""API for TickTick Integration bound to Home Assistant OAuth.""" | ||
|
||
from aiohttp import ClientSession | ||
|
||
from homeassistant.helpers import config_entry_oauth2_flow | ||
|
||
|
||
class AsyncConfigEntryAuth: | ||
"""Provide TickTick Integration authentication tied to an OAuth2 based config entry.""" | ||
|
||
def __init__( | ||
self, | ||
websession: ClientSession, | ||
oauth_session: config_entry_oauth2_flow.OAuth2Session, | ||
) -> None: | ||
"""Initialize TickTick Integration auth.""" | ||
self._websession = websession # Store the web session for later use | ||
self._oauth_session = oauth_session | ||
|
||
async def async_get_access_token(self) -> str: | ||
"""Return a valid access token.""" | ||
await self._oauth_session.async_ensure_token_valid() | ||
return self._oauth_session.token["access_token"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
"""Application credentials platform for the TickTick Integration integration.""" | ||
|
||
from homeassistant.components.application_credentials import AuthorizationServer | ||
from homeassistant.core import HomeAssistant | ||
|
||
from .const import OAUTH2_AUTHORIZE, OAUTH2_TOKEN | ||
|
||
|
||
async def async_get_authorization_server(hass: HomeAssistant) -> AuthorizationServer: | ||
"""Return authorization server.""" | ||
return AuthorizationServer( | ||
authorize_url=OAUTH2_AUTHORIZE, | ||
token_url=OAUTH2_TOKEN, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
"""Config flow for TickTick Integration.""" | ||
|
||
import logging | ||
|
||
from homeassistant.helpers import config_entry_oauth2_flow | ||
|
||
from .const import DOMAIN | ||
|
||
|
||
class OAuth2FlowHandler( | ||
config_entry_oauth2_flow.AbstractOAuth2FlowHandler, domain=DOMAIN | ||
): | ||
"""Config flow to handle TickTick Integration OAuth2 authentication.""" | ||
|
||
DOMAIN = DOMAIN | ||
|
||
@property | ||
def logger(self) -> logging.Logger: | ||
"""Return logger.""" | ||
return logging.getLogger(__name__) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
"""Constants for the TickTick Integration integration.""" | ||
|
||
DOMAIN = "ticktick" | ||
|
||
OAUTH2_AUTHORIZE = "https://ticktick.com/oauth/authorize" | ||
OAUTH2_TOKEN = "https://ticktick.com/oauth/token" | ||
TICKTICK_HOST = "api.ticktick.com" | ||
API = "open/v1" | ||
BASE_API_URL = f"{TICKTICK_HOST}/{API}" | ||
|
||
# === Parameters === # | ||
PROJECT_ID = "projectId" | ||
TASK_ID = "taskId" | ||
|
||
# === Endpoints === # | ||
|
||
# === Task Scope === | ||
GET_TASK = f"{BASE_API_URL}/project/{{{PROJECT_ID}}}/task/{{{TASK_ID}}}" | ||
CREATE_TASK = f"{BASE_API_URL}/task" | ||
UPDATE_TASK = f"{CREATE_TASK}/{{{TASK_ID}}}" | ||
COMPLETE_TASK = f"{BASE_API_URL}/project/{{{PROJECT_ID}}}/task/{{{TASK_ID}}}/complete" | ||
DELETE_TASK = GET_TASK | ||
|
||
# === Project Scope === | ||
GET_PROJECTS = f"{BASE_API_URL}/project" |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"services": { | ||
"get_task": { | ||
"service": "mdi:invoice-list" | ||
}, | ||
"create_task": { | ||
"service": "mdi:creation" | ||
}, | ||
"update_task": { | ||
"service": "mdi:arrow-up-bold-hexagon-outline" | ||
}, | ||
"complete_task": { | ||
"service": "mdi:check-decagram" | ||
}, | ||
"delete_task": { | ||
"service": "mdi:delete" | ||
}, | ||
"get_projects": { | ||
"service": "mdi:list-box" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,20 @@ | ||
{ | ||
"domain": "ticktick", | ||
"name": "TickTick", | ||
"codeowners": ["@Hantick"], | ||
"codeowners": [ | ||
"@Hantick" | ||
], | ||
"config_flow": true, | ||
"dependencies": [ | ||
"application_credentials" | ||
], | ||
"documentation": "/~https://github.com/Hantick/ticktick-home-assistant", | ||
"issue_tracker": "/~https://github.com/Hantick/ticktick-home-assistant/issues", | ||
"requirements": [ | ||
"requests<3.0.0" | ||
], | ||
"homekit": {}, | ||
"iot_class": "cloud_polling", | ||
"requirements": [], | ||
"ssdp": [], | ||
"zeroconf": [], | ||
"integration_type": "service", | ||
"version": "0.1.0" | ||
"version": "1.0.0" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
rules: | ||
# Bronze | ||
action-setup: todo | ||
appropriate-polling: todo | ||
brands: todo | ||
common-modules: todo | ||
config-flow-test-coverage: todo | ||
config-flow: todo | ||
dependency-transparency: todo | ||
docs-actions: todo | ||
docs-high-level-description: todo | ||
docs-installation-instructions: todo | ||
docs-removal-instructions: todo | ||
entity-event-setup: todo | ||
entity-unique-id: todo | ||
has-entity-name: todo | ||
runtime-data: todo | ||
test-before-configure: todo | ||
test-before-setup: todo | ||
unique-config-entry: todo | ||
|
||
# Silver | ||
action-exceptions: todo | ||
config-entry-unloading: todo | ||
docs-configuration-parameters: todo | ||
docs-installation-parameters: todo | ||
entity-unavailable: todo | ||
integration-owner: todo | ||
log-when-unavailable: todo | ||
parallel-updates: todo | ||
reauthentication-flow: todo | ||
test-coverage: todo | ||
|
||
# Gold | ||
devices: todo | ||
diagnostics: todo | ||
discovery-update-info: todo | ||
discovery: todo | ||
docs-data-update: todo | ||
docs-examples: todo | ||
docs-known-limitations: todo | ||
docs-supported-devices: todo | ||
docs-supported-functions: todo | ||
docs-troubleshooting: todo | ||
docs-use-cases: todo | ||
dynamic-devices: todo | ||
entity-category: todo | ||
entity-device-class: todo | ||
entity-disabled-by-default: todo | ||
entity-translations: todo | ||
exception-translations: todo | ||
icon-translations: todo | ||
reconfiguration-flow: todo | ||
repair-issues: todo | ||
stale-devices: todo | ||
|
||
# Platinum | ||
async-dependency: todo | ||
inject-websession: todo | ||
strict-typing: todo |
Oops, something went wrong.