일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- ConnectedHomeIP
- cluster
- 힐스테이트 광교산
- Espressif
- SK텔레콤
- 현대통신
- Home Assistant
- 국내주식
- Bestin
- MQTT
- matter
- raspberry pi
- 해외주식
- esp32
- 애플
- homebridge
- 월패드
- 미국주식
- 매터
- 나스닥
- 공모주
- 배당
- Apple
- 파이썬
- 티스토리챌린지
- RS-485
- Python
- 오블완
- 홈네트워크
- 코스피
- Today
- Total
YOGYUI
힐스테이트 광교산::난방/냉방 (반복) 타이머 기능 구현 본문
저번 주말에 폭설이 오더니, 요 며칠사이 엄청 추워졌다
글을 작성하고 있는 12월 17일 오전에도 눈이 내리고 있었다..
당분간 추위가 계속될 거라고 한다 ㅠ (추운게 더운것보다 훨씬 싫다)
https://www.delighti.co.kr/news/articleView.html?idxno=43181
난방비가 급격하게 올랐다는 기사들을 접하면 난방을 켜는게 약간 두렵기도 한데...
https://imnews.imbc.com/replay/2022/nwdesk/article/6435930_35744.html
난방을 하긴 해야겠다... 집안 실내 온도가 섭씨 20~21도밖에 안되니 집안에서 돌아다니는 것도 힘들다
(산 중턱에서의 삶의 비애지 뭐 ㅋㅋ)
어차피 관리비 걱정할만큼 벌이가 적은 것도 아니다!
힐스테이트 광교산 카카오톡 오픈채팅방에도 난방 관련 이야기가 많이 오가고 있는데, 1시간마다 10분씩만 난방을 가동하고자 하는데 방법을 모르겠다는 글이 보였다
내가 알기로 이런 반복적 타이머 기능은 월패드나 힐스테이트 홈네트워크 원격 제어 앱인 Hi-oT, 애플 홈, 구글 어시스턴트 등 접근할 수 있는 홈네트워크 플랫폼들에서는 유연하게 구성하기 힘들기 때문에, 라즈베리파이에서 구동되는 RS485 제어 코드 (파이썬)에 직접 구현하기로 했다
프로그래밍은 삶의 질을 직접적으로 향상시킬 수 있는 가장 좋은 도구다
[목표]
일정 시간동안 디바이스(난방/냉방 등)를 제어하는 타이머 기능 구현
On time, Off time을 설정해 켜고 끄는 동작을 반복할 수 있도록 해야 한다
1. 코딩 작업 (구현)
홈 네트워크에 소속된 모든 기기가 타이머 기능을 갖출 수 있는 부모 클래스 Device에 TimerOnOff라는 명칭으로 짜줬다 (Thermostat, Airconditioner 등 객체는 모두 Device 클래스를 상속)
class Device:
thread_timer_onoff = None
timer_onoff_params: dict
def __init__(self, name: str = 'Device', **kwargs):
self.timer_onoff_params = {
'on_time': 10, # unit: minute
'off_time': 50, # unit: minute
'repeat': True, # boolean
'off_when_terminate': True # device 켜진 상태에서 타이머 종료될 때 동작
}
if 'timer_onoff_ontime' in kwargs.keys():
self.timer_onoff_params['on_time'] = kwargs.get('timer_onoff_ontime')
if 'timer_onoff_offtime' in kwargs.keys():
self.timer_onoff_params['off_time'] = kwargs.get('timer_onoff_offtime')
if 'timer_onoff_repeat' in kwargs.keys():
self.timer_onoff_params['repeat'] = kwargs.get('timer_onoff_repeat')
def startTimerOnOff(self):
self.startThreadTimerOnOff()
def stopTimerOnOff(self):
self.stopThreadTimerOnOff()
def startThreadTimerOnOff(self):
if self.thread_timer_onoff is None:
self.thread_timer_onoff = ThreadDeviceTimerOnOff(self)
self.thread_timer_onoff.setDaemon(True)
self.thread_timer_onoff.sig_set_state.connect(self.sig_set_state.emit)
self.thread_timer_onoff.sig_terminated.connect(self.onThreadTimerOnOffTerminated)
on_time = self.timer_onoff_params['on_time']
off_time = self.timer_onoff_params['off_time']
repeat = self.timer_onoff_params['repeat']
self.thread_timer_onoff.setParams(on_time, off_time, repeat)
self.thread_timer_onoff.start()
def stopThreadTimerOnOff(self):
if self.thread_timer_onoff is not None:
self.thread_timer_onoff.stop()
def onThreadTimerOnOffTerminated(self):
del self.thread_timer_onoff
self.thread_timer_onoff = None
if self.timer_onoff_params['off_when_terminate']:
self.sig_set_state.emit(0)
else:
self.publish_mqtt()
def isTimerOnOffRunning(self) -> bool:
if self.thread_timer_onoff is not None:
return self.thread_timer_onoff.is_alive()
return False
def setTimerOnOffParams(self, on_time: float, off_time: float, repeat: bool):
self.timer_onoff_params['on_time'] = on_time
self.timer_onoff_params['off_time'] = off_time
self.timer_onoff_params['repeat'] = repeat
if self.thread_timer_onoff is not None:
self.thread_timer_onoff.setParams(on_time, off_time, repeat)
그리고 타이머 기능이 작동되는 쓰레드는 ThreadDeviceTimerOnOff라는 직관적인 이름으로 만들어줬다
(threading.Thread 상속)
class ThreadDeviceTimerOnOff(threading.Thread):
_keepAlive: bool = True
_dev: Device
_on_time: float = 10 # unit: minute
_off_time: float = 50 # unit: minute
_repeat: bool = True
def __init__(self, dev: Device):
threading.Thread.__init__(self, name=f'Device({dev}) On/Off Timer Thread')
self._dev = dev
self._timer_interval = 1 # unit: second
self.sig_terminated = Callback()
self.sig_set_state = Callback(int)
def run(self):
writeLog(f'{self.name} Started', self)
step = 0
tm: float = 0.
wait_for_transition: bool = False
while self._keepAlive:
if step == 0:
wait_for_transition = True
self.sig_set_state.emit(1)
tm_wait_state = time.perf_counter()
while wait_for_transition:
if self._dev.state == 1:
writeLog(f'{self._dev} state changed to {self._dev.state}', self)
wait_for_transition = False
if time.perf_counter() - tm_wait_state > 10:
writeLog('timeout! terminate timer on/off', self)
self._keepAlive = False
break
time.sleep(self._timer_interval)
tm = time.perf_counter()
step = 1
elif step == 1:
if time.perf_counter() - tm >= self._on_time * 60:
step = 2
elif step == 2:
wait_for_transition = True
self.sig_set_state.emit(0)
tm_wait_state = time.perf_counter()
while wait_for_transition:
if self._dev.state == 0:
writeLog(f'{self._dev} state changed to {self._dev.state}', self)
wait_for_transition = False
if time.perf_counter() - tm_wait_state > 10:
writeLog('timeout! terminate timer on/off', self)
self._keepAlive = False
break
time.sleep(self._timer_interval)
tm = time.perf_counter()
step = 3
elif step == 3:
if time.perf_counter() - tm >= self._off_time * 60:
if self._repeat:
step = 0
else:
break
time.sleep(self._timer_interval)
writeLog(f'{self.name} Terminated', self)
self.sig_terminated.emit()
def stop(self):
self._keepAlive = False
def setParams(self, on_time: float, off_time: float, repeat: bool):
self._on_time = on_time
self._off_time = off_time
self._repeat = repeat
코드 가독성을 높이기 위해 쓰레드 내부 동작 (run 메서드) 코드는 정말 직관적으로 구현했다
(드물게 내 코드를 읽으시는 분들이 계시더라는... 솔직히 이렇게 짜는게 훨씬 쉽긴 하다 ㅎㅎ)
- step=0: 디바이스를 켜는 콜백 호출 (set state as 1) 후 디바이스의 현재 상태가 1이 될 때까지 대기
- step=1: 설정된 On Time만큼 아무것도 하지 않는다
- step=2: 디바이스를 끄는 콜백 호출 (set state as 0) 후 디바이스의 현재 상태가 0이 될 때까지 대기
- step=3: 설정된 Off Time만큼 아무것도 하지 않는다, 그리고 반복(repeat)가 설정되어 있으면 다시 step을 0으로 만든다
요렇게 단계별로 '켜기' - '대기' - '끄기' - '대기' 를 반복하게 만들었으며, 외부 호출(stop 메서드)에 의해 쓰레드가 즉시 종료될 수 있게 해줬다
반복(repeat) 플래그를 0으로 설정하면 1번만 수행되니, 냉/난방 말고 다른 기기(조명, 전열교환기 등)들에도 유용하게 사용할 수 있는 기능일 것 같다
※ On Time과 Off Time은 10분, 50분을 default값으로 구현했는데, 나중에 MQTT를 통해서건, 웹 API를 통해서건 변경할 수 있게 추가해야겠다
그리고 Home 클래스는 내부에 소속된 Device들의 콜백을 다음과 같이 처리하게 구현했다
(일단은 난방과 냉방만 동작하게~)
class Home:
device_list: List[Device]
def initialize(self, init_service: bool, connect_rs485: bool):
self.initialize(init_service, False)
def initialize(self, init_service: bool, connect_rs485: bool):
for dev in self.device_list:
dev.sig_set_state.connect(partial(self.onDeviceSetState, dev))
def onDeviceSetState(self, dev: Device, state: int):
if isinstance(dev, AirConditioner):
self.command(
device=dev,
category='active',
target=state
)
elif isinstance(dev, Thermostat):
self.command(
device=dev,
category='state',
target='HEAT' if state else 'OFF'
)
난방(Thermostat)과 냉방(Airconditioner)은 현재 On/Off 타이머가 동작중인지를 MQTT로 메시지 발행(publish)하는 구문만 추가해줬다 (홈네트워크 플랫폼에서 타이머가 동작중인지 여부를 알아야 한다)
class AirConditioner(Device):
def publish_mqtt(self):
if self.state:
state = 'COOLING'
else:
state = 'INACTIVE'
obj = {
"active": self.state,
"state": state,
"currentTemperature": self.temp_current,
"targetTemperature": self.temp_config,
"timer": int(self.isTimerOnOffRunning())
}
if self.rotation_speed == 0x02: # 미풍
obj['rotationspeed'] = 50
obj['rotationspeed_name'] = 'Min'
elif self.rotation_speed == 0x03: # 약풍
obj['rotationspeed'] = 75
obj['rotationspeed_name'] = 'Medium'
elif self.rotation_speed == 0x04: # 강풍
obj['rotationspeed'] = 100
obj['rotationspeed_name'] = 'Max'
else:
obj['rotationspeed'] = 25
obj['rotationspeed_name'] = 'Auto'
if self.mqtt_client is not None:
self.mqtt_client.publish(self.mqtt_publish_topic, json.dumps(obj), 1)
class Thermostat(Device):
def publish_mqtt(self):
obj = {
"state": 'HEAT' if self.state == 1 else 'OFF',
"currentTemperature": self.temp_current,
"targetTemperature": self.temp_config,
"timer": int(self.isTimerOnOffRunning())
}
if self.mqtt_client is not None:
self.mqtt_client.publish(self.mqtt_publish_topic, json.dumps(obj), 1)
생각보다 손봐야될 코드가 많다
그래도 이정도면 모듈화 구현을 통해 유지보수가 상당히 빠르고 쉽다(고 자평해본다)
2. Homebridge 액세서리 추가
홈브릿지 MqttThing 플러그인의 switch 액세서리로 활용해보자
테스트를 위해 밤에 내가 자는 공간인 침실(방 인덱스=2)에만 냉방, 난방 타이머 액세서리를 추가해줬다
{
"accessory": "mqttthing",
"type": "switch",
"name": "Bedroom AirConditioner Timer (MQTT)",
"topics": {
"getOn": {
"topic": "home/hillstate/airconditioner/state/2",
"apply": "return (JSON.parse(message).timer == 1);"
},
"setOn": {
"topic": "home/hillstate/airconditioner/command/2",
"apply": "return JSON.stringify({timer: message});"
}
},
"integerValue": true,
"onValue": 1,
"offValue": 0,
"logMqtt": false
},
{
"accessory": "mqttthing",
"type": "switch",
"name": "Bedroom Thermostat Timer (MQTT)",
"topics": {
"getOn": {
"topic": "home/hillstate/thermostat/state/2",
"apply": "return (JSON.parse(message).timer == 1);"
},
"setOn": {
"topic": "home/hillstate/thermostat/command/2",
"apply": "return JSON.stringify({timer: message});"
}
},
"integerValue": true,
"onValue": 1,
"offValue": 0,
"logMqtt": false
}
MQTT 토픽(topic)은
- 난방: home/hillstate/thermostat/state/{방 인덱스}
- 냉방: home/hillstate/airconditioner/state/{방 인덱스}
페이로드(payload)는 단순히 {timer: 1} 혹은 {timer: 0}으로 타이머를 켜고 끈다
액세서리 스크립트 추가 후 homebridge를 재시작해보면 타이머 액세서리 (스위치)를 애플 홈 앱에서 볼 수 있다
난방 타이머 스위치를 켜니 난방이 즉시 동작하기 시작했다~ Good!
하루종일 켜져있는 걸 방지하기 위해 매일 오전 7시 모든 난방과 난방 타이머 동작을 해제하는 자동화도 만들어주자
3. 테스트
16일 저녁에 영화 한편 조지고 자정 무렵부터 코딩을 시작해서 1시간 정도 걸려서 작업을 마무리했다
테스트를 위해 새벽 2시 무렵 애플 홈 앱에서 타이머를 켜고 잠자리에 들었고, 기상 후 라즈베리파이의 콘솔 로그를 확인해봤다
<02:08:01.844677> [Home] MQTT Message: home/hillstate/thermostat/command/2: {'timer': 1}
<02:08:01.845606> [ThreadDeviceTimerOnOff] <Thermostat Room Idx: 2> On/Off Timer Thread Started
<02:08:01.846065> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 2>
category: state
target: HEAT
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<02:08:01.851787> [ParserVarious] Send >> F7 0B 01 18 02 46 12 01 00 B2 EE
<02:08:05.359135> [ThreadCommandQueue] set_state_common::send # = 35, elapsed = 3512.13 msec
<02:08:05.850553> [ThreadDeviceTimerOnOff] <Thermostat Room Idx: 2> state changed to 1
<02:18:08.321300> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 2>
category: state
target: OFF
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<02:18:08.322397> [ParserVarious] Send >> F7 0B 01 18 02 46 12 04 00 B7 EE
<02:18:08.522031> [ThreadCommandQueue] set_state_common::send # = 2, elapsed = 200.358 msec
<02:18:09.322035> [ThreadDeviceTimerOnOff] <Thermostat Room Idx: 2> state changed to 0
<03:08:11.669890> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 2>
category: state
target: HEAT
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<03:08:11.671172> [ParserVarious] Send >> F7 0B 01 18 02 46 12 01 00 B2 EE
<03:08:12.372871> [ThreadCommandQueue] set_state_common::send # = 7, elapsed = 702.522 msec
<03:08:12.670812> [ThreadDeviceTimerOnOff] <Thermostat Room Idx: 2> state changed to 1
<03:18:15.147517> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 2>
category: state
target: OFF
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<03:18:15.148947> [ParserVarious] Send >> F7 0B 01 18 02 46 12 04 00 B7 EE
<03:18:15.348403> [ThreadCommandQueue] set_state_common::send # = 2, elapsed = 200.533 msec
<03:18:16.148184> [ThreadDeviceTimerOnOff] <Thermostat Room Idx: 2> state changed to 0
<04:08:18.401166> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 2>
category: state
target: HEAT
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<04:08:18.402970> [ParserVarious] Send >> F7 0B 01 18 02 46 12 01 00 B2 EE
<04:08:19.400831> [ThreadDeviceTimerOnOff] <Thermostat Room Idx: 2> state changed to 1
<04:08:19.404979> [ThreadCommandQueue] set_state_common::send # = 10, elapsed = 1003.16 msec
<04:18:21.888466> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 2>
category: state
target: OFF
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<04:18:21.890100> [ParserVarious] Send >> F7 0B 01 18 02 46 12 04 00 B7 EE
<04:18:22.791491> [ThreadCommandQueue] set_state_common::send # = 9, elapsed = 902.532 msec
<04:18:22.888564> [ThreadDeviceTimerOnOff] <Thermostat Room Idx: 2> state changed to 0
<05:08:25.168969> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 2>
category: state
target: HEAT
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<05:08:25.170529> [ParserVarious] Send >> F7 0B 01 18 02 46 12 01 00 B2 EE
<05:08:26.169792> [ThreadDeviceTimerOnOff] <Thermostat Room Idx: 2> state changed to 1
<05:08:26.171765> [ThreadCommandQueue] set_state_common::send # = 10, elapsed = 1002.48 msec
<05:18:28.640335> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 2>
category: state
target: OFF
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<05:18:28.641546> [ParserVarious] Send >> F7 0B 01 18 02 46 12 04 00 B7 EE
<05:18:29.544230> [ThreadCommandQueue] set_state_common::send # = 9, elapsed = 903.559 msec
<05:18:29.639822> [ThreadDeviceTimerOnOff] <Thermostat Room Idx: 2> state changed to 0
<06:08:31.991177> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 2>
category: state
target: HEAT
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<06:08:31.992956> [ParserVarious] Send >> F7 0B 01 18 02 46 12 01 00 B2 EE
<06:08:32.192356> [ThreadCommandQueue] set_state_common::send # = 2, elapsed = 200.601 msec
<06:08:32.991273> [ThreadDeviceTimerOnOff] <Thermostat Room Idx: 2> state changed to 1
<06:11:41.415318> [ParserVarious] Timestamp Packet: F7 14 01 44 0C 62 00 00 16 0C 11 06 0B 27 01 01 0A 00 E3 EE
<06:18:35.436598> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 2>
category: state
target: OFF
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<06:18:35.438306> [ParserVarious] Send >> F7 0B 01 18 02 46 12 04 00 B7 EE
<06:18:36.739934> [ThreadCommandQueue] set_state_common::send # = 13, elapsed = 1302.9 msec
<06:18:37.437668> [ThreadDeviceTimerOnOff] <Thermostat Room Idx: 2> state changed to 0
<07:00:02.519101> [Home] MQTT Message: home/hillstate/thermostat/command/4: {'state': 'OFF'}
<07:00:02.519763> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 4>
category: state
target: OFF
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<07:00:02.520191> [Home] MQTT Message: home/hillstate/thermostat/command/4: {'targetTemperature': 30}
<07:00:02.530328> [Home] MQTT Message: home/hillstate/thermostat/command/2: {'timer': 0}
<07:00:02.530881> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 4>
category: temperature
target: 30
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<07:00:02.538440> [Home] MQTT Message: home/hillstate/thermostat/command/2: {'targetTemperature': 25}
<07:00:02.539508> [Home] MQTT Message: home/hillstate/thermostat/command/3: {'state': 'OFF'}
<07:00:02.539959> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 2>
category: temperature
target: 25
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<07:00:02.541167> [Home] MQTT Message: home/hillstate/thermostat/command/2: {'state': 'OFF'}
<07:00:02.542695> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 3>
category: state
target: OFF
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<07:00:02.543571> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 2>
category: state
target: OFF
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<07:00:02.545171> [Home] MQTT Message: home/hillstate/thermostat/command/3: {'targetTemperature': 30}
<07:00:02.545712> [Home] MQTT Message: home/hillstate/thermostat/command/1: {'state': 'OFF'}
<07:00:02.545893> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 3>
category: temperature
target: 30
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<07:00:02.548049> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 1>
category: state
target: OFF
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<07:00:02.546310> [Home] MQTT Message: home/hillstate/thermostat/command/1: {'targetTemperature': 25}
<07:00:02.552566> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 1>
category: temperature
target: 25
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
<07:00:03.357626> [ThreadDeviceTimerOnOff] Device(<Thermostat Room Idx: 2>) On/Off Timer Thread Terminated
<07:00:03.358916> [ThreadCommandQueue] Get Command Queue:
{
device: <Thermostat Room Idx: 2>
category: state
target: OFF
parser: <ParserVarious.ParserVarious object at 0xb26d8590>
}
오전 2시 8분 타이머 쓰레드가 가동되기 시작했고, 10분간 켜지고 50분간 꺼져서 1시간에 10분씩 가동되었다
그리고 애플 홈 자동화에 의해 오전 7시 모든 난방과 난방 타이머의 작동이 중단되었다
(콘솔 로그상으로는 원하는대로 동작이 잘 됐다~)
Home Assistant의 로그북을 통해 동작 여부를 확인해보자
1시간 간격으로 10분씩 난방이 정상적으로 가동됐다 (희망온도=25도)
월패드의 온도 센서로 감지하는 실내온도(현재온도)는 23도로 큰 변동이 없다 (사실 이 녀석은 크게 믿지 않는게 좋다)
방 벽면에 부착해둔 Aqara 온습도 센서의 온도 모니터링 결과를 확인해보자
난방이 되지 않은 16일 오후에는 침실 실내온도가 21도 수준이었는데, 타이머가 가동된 17일 오전 2시 ~ 오전 7시에는 실내 온도가 23.5도 정도로 유지된 것을 확인할 수 있다 (난방 가동 희망온도는 25도)
이정도면 충분하지 않을까? 라는 생각은 든다 ㅎㅎ
※ 실제로 오전 8시 기상했을 때 방바닥에 미미하게 온기가 남아있었다
4. 마무리
위에서 말한 기능깃허브 저장소에 'device_onoff_timer' 이름의 브랜치로 커밋해뒀다
https://github.com/YOGYUI/HomeNetwork/tree/device_onoff_timer
[TODO]
타이머 파라미터(on time, off time, repeat)를 외부에서 수정할 수 있는 기능 추가 (MQTT, 웹 API)- Home Assistant 타이머 액세서리 추가 (구글 어시스턴트 연동)
이래저래 타이머 On Time과 Off Time을 조정해보면서 최적의 실내온도를 유지할 수 있는 방안을 찾아봐야겠다 ㅎㅎ (실내 온도가 일정 수준 이하로 떨어지면 타이머를 자동으로 켜는 자동화도 만들어볼만 하다)
이제 자는 동안 추위에 떨 일은 없겠구먼~
※ 여름되면 냉방(에어컨) 타이머도 유용하게 사용할 수 있을 것 같다!
[22.12.20] 추가
타이머 파라미터 (On time, Off time, Repeat 여부)를 수정할 수 있는 웹페이지를 추가해줬다 (core: python - Flask)
※ POST 방식의 web API로 간단하게 구현
프론트엔드 개발은 문외한이라 그냥 필요한 최소한의 기능만 충족시키는 걸로~ (UI/UX bye bye~)
웹페이지 추가된 소스코드는 동일 브랜치(device_onoff_timer)
commit id 0c033df16aae216e788306cec20137bf6a6dca0d 로 푸시해뒀다
이제 거실 + 방3개 모두 에어컨/난방 각각의 타이머 관련 파라미터를 요리조리 수정할 수 있다
Homebridge에도 타이머 관련 액세서리 (스위치) 총 8개 구현 완료~
매일 오전 에어컨과 난방 및 타이머들을 종료시켜주는 자동화도 홈 앱에서 구현 완료~
끝~!
'홈네트워크(IoT) > 힐스테이트 광교산' 카테고리의 다른 글
현대통신 월패드 RS-485 연동 소스코드(python) 개선 작업 (4) | 2023.06.19 |
---|---|
힐스테이트 광교산::일괄소등 스위치 RS-485 패킷 분석 및 애플 홈 연동 (4) | 2023.06.04 |
힐스테이트 광교산::공동출입문용 RFID 스티커형 태그 복사 (스마트폰) (1) | 2022.11.21 |
힐스테이트 광교산::주방 싱크대 LED 조명 IoT 연동 (2) | 2022.11.19 |
LG 물걸레 로봇청소기 (코드제로 M9) + 싱크대 절수 페달 연동 (ThinQ + Homebridge) (0) | 2022.10.29 |