mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Part 3: Add support for incoming sms events (#37015)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
parent
8ca5a04a5d
commit
a1ac1fb091
@ -6,6 +6,10 @@ from gammu.asyncworker import ( # pylint: disable=import-error, no-member
|
||||
GammuAsyncWorker,
|
||||
)
|
||||
|
||||
from homeassistant.core import callback
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -15,6 +19,120 @@ class Gateway:
|
||||
def __init__(self, worker, hass):
|
||||
"""Initialize the sms gateway."""
|
||||
self._worker = worker
|
||||
self._hass = hass
|
||||
|
||||
async def init_async(self):
|
||||
"""Initialize the sms gateway asynchronously."""
|
||||
try:
|
||||
await self._worker.set_incoming_sms_async()
|
||||
except gammu.ERR_NOTSUPPORTED:
|
||||
_LOGGER.warning("Your phone does not support incoming SMS notifications!")
|
||||
else:
|
||||
await self._worker.set_incoming_callback_async(self.sms_callback)
|
||||
|
||||
def sms_callback(self, state_machine, callback_type, callback_data):
|
||||
"""Receive notification about incoming event.
|
||||
|
||||
@param state_machine: state machine which invoked action
|
||||
@type state_machine: gammu.StateMachine
|
||||
@param callback_type: type of action, one of Call, SMS, CB, USSD
|
||||
@type callback_type: string
|
||||
@param data: event data
|
||||
@type data: hash
|
||||
"""
|
||||
_LOGGER.debug(
|
||||
"Received incoming event type:%s,data:%s", callback_type, callback_data
|
||||
)
|
||||
entries = self.get_and_delete_all_sms(state_machine)
|
||||
_LOGGER.debug("SMS entries:%s", entries)
|
||||
data = list()
|
||||
|
||||
for entry in entries:
|
||||
decoded_entry = gammu.DecodeSMS(entry)
|
||||
message = entry[0]
|
||||
_LOGGER.debug("Processing sms:%s,decoded:%s", message, decoded_entry)
|
||||
if decoded_entry is None:
|
||||
text = message["Text"]
|
||||
else:
|
||||
text = ""
|
||||
for inner_entry in decoded_entry["Entries"]:
|
||||
if inner_entry["Buffer"] is not None:
|
||||
text = text + inner_entry["Buffer"]
|
||||
|
||||
event_data = dict(
|
||||
phone=message["Number"], date=str(message["DateTime"]), message=text
|
||||
)
|
||||
|
||||
_LOGGER.debug("Append event data:%s", event_data)
|
||||
data.append(event_data)
|
||||
|
||||
self._hass.add_job(self._notify_incoming_sms, data)
|
||||
|
||||
# pylint: disable=no-self-use
|
||||
def get_and_delete_all_sms(self, state_machine, force=False):
|
||||
"""Read and delete all SMS in the modem."""
|
||||
# Read SMS memory status ...
|
||||
memory = state_machine.GetSMSStatus()
|
||||
# ... and calculate number of messages
|
||||
remaining = memory["SIMUsed"] + memory["PhoneUsed"]
|
||||
start_remaining = remaining
|
||||
# Get all sms
|
||||
start = True
|
||||
entries = list()
|
||||
all_parts = -1
|
||||
all_parts_arrived = False
|
||||
_LOGGER.debug("Start remaining:%i", start_remaining)
|
||||
|
||||
try:
|
||||
while remaining > 0:
|
||||
if start:
|
||||
entry = state_machine.GetNextSMS(Folder=0, Start=True)
|
||||
all_parts = entry[0]["UDH"]["AllParts"]
|
||||
part_number = entry[0]["UDH"]["PartNumber"]
|
||||
is_single_part = all_parts == 0
|
||||
is_multi_part = 0 <= all_parts < start_remaining
|
||||
_LOGGER.debug("All parts:%i", all_parts)
|
||||
_LOGGER.debug("Part Number:%i", part_number)
|
||||
_LOGGER.debug("Remaining:%i", remaining)
|
||||
all_parts_arrived = is_multi_part or is_single_part
|
||||
_LOGGER.debug("Start all_parts_arrived:%s", all_parts_arrived)
|
||||
start = False
|
||||
else:
|
||||
entry = state_machine.GetNextSMS(
|
||||
Folder=0, Location=entry[0]["Location"]
|
||||
)
|
||||
|
||||
if all_parts_arrived or force:
|
||||
remaining = remaining - 1
|
||||
entries.append(entry)
|
||||
|
||||
# delete retrieved sms
|
||||
_LOGGER.debug("Deleting message")
|
||||
state_machine.DeleteSMS(Folder=0, Location=entry[0]["Location"])
|
||||
else:
|
||||
_LOGGER.debug("Not all parts have arrived")
|
||||
break
|
||||
|
||||
except gammu.ERR_EMPTY:
|
||||
# error is raised if memory is empty (this induces wrong reported
|
||||
# memory status)
|
||||
_LOGGER.info("Failed to read messages!")
|
||||
|
||||
# Link all SMS when there are concatenated messages
|
||||
entries = gammu.LinkSMS(entries)
|
||||
|
||||
return entries
|
||||
|
||||
@callback
|
||||
def _notify_incoming_sms(self, messages):
|
||||
"""Notify hass when an incoming SMS message is received."""
|
||||
for message in messages:
|
||||
event_data = {
|
||||
"phone": message["phone"],
|
||||
"date": message["date"],
|
||||
"text": message["message"],
|
||||
}
|
||||
self._hass.bus.async_fire(f"{DOMAIN}.incoming_sms", event_data)
|
||||
|
||||
async def send_sms_async(self, message):
|
||||
"""Send sms message via the worker."""
|
||||
@ -40,6 +158,7 @@ async def create_sms_gateway(config, hass):
|
||||
worker.configure(config)
|
||||
await worker.init_async()
|
||||
gateway = Gateway(worker, hass)
|
||||
await gateway.init_async()
|
||||
return gateway
|
||||
except gammu.GSMError as exc: # pylint: disable=no-member
|
||||
_LOGGER.error("Failed to initialize, error %s", exc)
|
||||
|
Loading…
x
Reference in New Issue
Block a user