Skip to content

Commit

Permalink
First commit and set version to v0.0.2
Browse files Browse the repository at this point in the history
  • Loading branch information
georgezhao2010 authored Jul 1, 2021
1 parent 25a3002 commit dcd7557
Show file tree
Hide file tree
Showing 5 changed files with 244 additions and 0 deletions.
103 changes: 103 additions & 0 deletions custom_components/tencent_stock/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import logging
import async_timeout
import requests
import datetime
import re
from datetime import timedelta
from homeassistant.helpers import discovery
from homeassistant.core import HomeAssistant
from.const import (DOMAIN,
REPOS_API_URL,
CONF_EXCHANGE,
CONF_STOCK,
MIN_UPDATE_INTERVAL,
MAX_UPDATE_INTERVAL,
TIME_SLICES)
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator


_LOGGER = logging.getLogger(__name__)


async def async_setup(hass: HomeAssistant, hass_config: dict):
config = hass_config[DOMAIN]
coordinator = StockCorrdinator(hass, config)
hass.data[DOMAIN] = coordinator
await coordinator.async_refresh()
hass.async_create_task(discovery.async_load_platform(
hass, "sensor", DOMAIN, config, hass_config))

return True

UPDATE_INTERVAL = timedelta(seconds=MIN_UPDATE_INTERVAL)


class StockCorrdinator(DataUpdateCoordinator):
_tencent_data_format = ['stock', 'unused', 'name', '股票代码', '当前价格', '昨收', '今开', '成交量(手)', '外盘', '内盘',
'买一', '买一量(手)', '买二', '买二量(手)', '买三', '买三量(手)', '买四', '买四量(手)', '买五',
'买五量(手)', '卖一', '卖一量(手)', '卖二', '卖二量(手)', '卖三', '卖三量(手)', '卖四',
'卖四量(手)', '卖五', '卖五量(手)', 'unknown1', 'datetime', '涨跌', '涨跌(%)', '最高', '最低',
'价格/成交量(手)/成交额', '成交量(手)', '成交额(万)', '换手率', '市盈率', 'unknown2', '最高1', '最低1', '振幅',
'流通市值', '总市值', '市净率', '涨停价', '跌停价', '量比', '委差', '均价', '市盈(动)', '市盈(静)']
_tencent_data_patten = re.compile(r'v_([-/\.\w]*)="([\w]*)' + (r'~([-/\.\w]*)' * (len(_tencent_data_format) - 2)))

def __init__(self, hass, config):
self._hass = hass
self._quest_url = REPOS_API_URL
if config is not None and "time_slices" in config:
self._time_slice = config["time_slices"]
else:
self._time_slice = TIME_SLICES
_LOGGER.debug(self._time_slice)
self._count = MAX_UPDATE_INTERVAL
for exchange, stocks in config["stocks"].items():
for stock in stocks:
self._quest_url = self._quest_url + exchange + stock + ","

super().__init__(
hass,
_LOGGER,
name=DOMAIN,
update_interval=UPDATE_INTERVAL,
)

def format_response_data(self, res_data):
res_data = res_data.replace(" ", "")
data = "".join(res_data)
data = self._tencent_data_patten.finditer(data)
result_list = {}
for item in data:
assert len(self._tencent_data_format) == len(item.groups())
single = dict(zip(self._tencent_data_format, item.groups()))
result_list[single["stock"]] = single
return result_list

def in_time_slice(self, ):
now_time = datetime.datetime.now()
if now_time.weekday() > 4:
return False
for single_slice in self._time_slice:
begin_time = datetime.datetime.strptime(str(datetime.datetime.now().date()) + single_slice["begin_time"],
'%Y-%m-%d%H:%M') - datetime.timedelta(minutes=2)
end_time = datetime.datetime.strptime(str(datetime.datetime.now().date()) + single_slice["end_time"],
'%Y-%m-%d%H:%M') + datetime.timedelta(minutes=2)
if begin_time <= now_time <= end_time:
return True
return False

async def _async_update_data(self):
data = self.data
if self.in_time_slice() or self._count >= MAX_UPDATE_INTERVAL:
self._count = 0
async with async_timeout.timeout(3):
r = await self._hass.async_add_executor_job(
requests.get,
self._quest_url
)
if r.status_code == 200:
data = self.format_response_data(r.text)
_LOGGER.debug(f"Successful to update stock data {data}")
else:
self._count = self._count + MIN_UPDATE_INTERVAL
_LOGGER.debug(f"Now time not in slice, count = {self._count}")
return data
9 changes: 9 additions & 0 deletions custom_components/tencent_stock/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
tencent_stock:
time_slices:
- begin_time: '9:15'
end_time: '11:30'
- begin_time: '13:00'
end_time: '15:00'
stocks:
sh: ['000001','600029','600519']
sz: ['399001','399006']
7 changes: 7 additions & 0 deletions custom_components/tencent_stock/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
DOMAIN = "tencent_stock"
REPOS_API_URL = "https://qt.gtimg.cn/q="
CONF_EXCHANGE = "exchange"
CONF_STOCK = "stock"
MIN_UPDATE_INTERVAL = 10
MAX_UPDATE_INTERVAL = 36000
TIME_SLICES = [{"begin_time": "9:15", "end_time": "11:30"}, {"begin_time": "13:00", "end_time": "15:00"}]
12 changes: 12 additions & 0 deletions custom_components/tencent_stock/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"domain": "tencent_stock",
"name": "Tencent Stocks",
"version": "v0.0.2",
"config_flow": true,
"documentation": "https://github.com/georgezhao2010/tencent_stock",
"issue_tracker": "https://github.com/georgezhao2010/tencent_stock/issues",
"requirements": [],
"dependencies": [],
"iot_class": "cloud_polling",
"codeowners": ["@georgezhao2010"]
}
113 changes: 113 additions & 0 deletions custom_components/tencent_stock/sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import logging
from .const import DOMAIN
from homeassistant.const import STATE_UNKNOWN
from homeassistant.helpers.update_coordinator import CoordinatorEntity


_LOGGER = logging.getLogger(__name__)


async def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
sensors = []
coordinator = hass.data[DOMAIN]
for exchange, stocks in discovery_info["stocks"].items():
for stock in stocks:
sensors.append(StockSensor(coordinator, exchange + stock))
async_add_devices(sensors, True)


class StockSensor(CoordinatorEntity):
def __init__(self, coordinator, stock):
super().__init__(coordinator)
self._coordinator = coordinator
self._stock = stock
self._unique_id = f"{DOMAIN}.stock_{stock}"
self.entity_id = self._unique_id
self._is_index = True if (stock[0:2] == "sh" and stock[2:5] == "000") \
or (stock[0:2] == "sz" and stock[2:5] == "399") else False

def get_value(self, key):
data = self._coordinator.data.get(self._stock)
if data is not None:
return data.get(key)
else:
return STATE_UNKNOWN

@staticmethod
def sign(str_val):
if float(str_val) != 0 and str_val[0:1] != "-":
return "+" + str_val
return str_val

@property
def name(self):
return f"{self.get_value('name')}({self._stock}) [{self.sign(self.get_value('涨跌'))}" \
f"({self.sign(self.get_value('涨跌(%)'))}%)]"

@property
def unique_id(self):
return self._unique_id

@property
def state(self):
return float(self.get_value('当前价格'))

@property
def device_id(self):
return self.device_id

@property
def device_state_attributes(self) -> dict:
ret = {
"股票代码": self.get_value("股票代码"),
"当前价格": self.get_value("当前价格"),
"昨收": self.get_value("昨收"),
"今开": self.get_value("今开"),
"成交量": self.get_value("成交量(手)"),
"外盘": self.get_value("外盘"),
"内盘": self.get_value("内盘"),
"涨跌": self.sign(self.get_value("涨跌")),
"涨跌幅": self.sign(self.get_value("涨跌(%)")) + "%",
"最高": self.get_value("最高"),
"最低": self.get_value("最低"),
"成交额": self.get_value("成交额(万)"),
"振幅": self.get_value("振幅") + "%",
}

if not self._is_index:
ret.update({
"卖五(" + self.get_value("卖五") + ")": self.get_value("卖五量(手)"),
"卖四(" + self.get_value("卖四") + ")": self.get_value("卖四量(手)"),
"卖三(" + self.get_value("卖三") + ")": self.get_value("卖三量(手)"),
"卖二(" + self.get_value("卖二") + ")": self.get_value("卖二量(手)"),
"卖一(" + self.get_value("卖一") + ")": self.get_value("卖一量(手)"),
"买一(" + self.get_value("买一") + ")": self.get_value("买一量(手)"),
"买二(" + self.get_value("买二") + ")": self.get_value("买二量(手)"),
"买三(" + self.get_value("买三") + ")": self.get_value("买三量(手)"),
"买四(" + self.get_value("买四") + ")": self.get_value("买四量(手)"),
"买五(" + self.get_value("买五") + ")": self.get_value("买五量(手)"),
"换手率": self.get_value("换手率") + "%",
"市盈率": self.get_value("市盈率"),
"流通市值": self.get_value("流通市值"),
"总市值": self.get_value("总市值"),
"市净率": self.get_value("市净率"),
"量比": self.get_value("量比"),
"均价": self.get_value("均价"),
"涨停价": self.get_value("涨停价"),
"跌停价": self.get_value("跌停价"),
"委差": self.get_value("委差"),
"市盈(动)": self.get_value("市盈(动)"),
"市盈(静)": self.get_value("市盈(静)")
})
return ret

@property
def unit_of_measurement(self):
if self._is_index:
return "点"
else:
return "元"

@property
def icon(self):
return "hass:pulse"

0 comments on commit dcd7557

Please sign in to comment.