Skip to content

Commit

Permalink
Merge pull request #609 from steersbob/feature/storage-patch
Browse files Browse the repository at this point in the history
Block names on controller
  • Loading branch information
steersbob authored May 8, 2024
2 parents 3c23a10 + b28ea4a commit b8d18d7
Show file tree
Hide file tree
Showing 49 changed files with 1,124 additions and 1,757 deletions.
9 changes: 3 additions & 6 deletions brewblox_devcon_spark/broadcast.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from contextlib import asynccontextmanager
from datetime import timedelta

from . import const, mqtt, spark_api, state_machine, utils
from . import mqtt, spark_api, state_machine, utils
from .block_analysis import calculate_claims, calculate_relations
from .models import HistoryEvent, ServiceStateEvent, ServiceStateEventData

Expand All @@ -35,11 +35,8 @@ async def run(self):
logged_blocks = await self.api.read_all_logged_blocks()

# Convert list to key/value format suitable for history
history_data = {
block.id: block.data
for block in logged_blocks
if not block.id.startswith(const.GENERATED_ID_PREFIX)
}
history_data = {block.id: block.data
for block in logged_blocks}

mqtt_client.publish(self.history_topic,
HistoryEvent(
Expand Down
58 changes: 19 additions & 39 deletions brewblox_devcon_spark/codec/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import logging
from base64 import b64decode, b64encode
from contextvars import ContextVar
from typing import Optional

from google.protobuf import json_format

Expand All @@ -15,29 +14,13 @@
from . import lookup, pb2, time_utils, unit_conversion
from .processor import ProtobufProcessor

DEPRECATED_TYPE_INT = 65533
DEPRECATED_TYPE_STR = 'DeprecatedObject'
UNKNOWN_TYPE_STR = 'UnknownType'
ERROR_TYPE_STR = 'ErrorObject'

LOGGER = logging.getLogger(__name__)
CV: ContextVar['Codec'] = ContextVar('codec.Codec')


def split_type(type_str: str) -> tuple[str, Optional[str]]:
if '.' in type_str:
return tuple(type_str.split('.', 1))
else:
return type_str, None


def join_type(blockType: str, subtype: Optional[str]) -> str:
if subtype:
return f'{blockType}.{subtype}'
else:
return blockType


class Codec:
def __init__(self, filter_values=True):
self._processor = ProtobufProcessor(filter_values)
Expand Down Expand Up @@ -112,15 +95,15 @@ def encode_payload(self,
if payload.blockType is None:
return EncodedPayload(
blockId=payload.blockId,
name=payload.name,
)

if payload.blockType == DEPRECATED_TYPE_STR:
actual_id = payload.content['actualId']
content_bytes = actual_id.to_bytes(2, 'little')
if payload.blockType == 'Deprecated':
return EncodedPayload(
blockId=payload.blockId,
blockType=DEPRECATED_TYPE_INT,
content=b64encode(content_bytes).decode(),
blockType=lookup.BlockType.Value('Deprecated'),
name=payload.name,
content=payload.content['bytes'],
)

# Interface-only payload
Expand All @@ -130,12 +113,12 @@ def encode_payload(self,
return EncodedPayload(
blockId=payload.blockId,
blockType=impl.type_int,
name=payload.name,
)

# Payload contains data
impl = next((v for v in lookup.CV_OBJECTS.get()
if v.type_str == payload.blockType
and v.subtype_str == payload.subtype))
if v.type_str == payload.blockType))

message = impl.message_cls()
payload = self._processor.pre_encode(message.DESCRIPTOR,
Expand All @@ -147,14 +130,14 @@ def encode_payload(self,
return EncodedPayload(
blockId=payload.blockId,
blockType=impl.type_int,
subtype=impl.subtype_int,
name=payload.name,
content=content,
maskMode=payload.maskMode,
maskFields=payload.maskFields
)

except StopIteration:
msg = f'No codec entry found for {payload.blockType}.{payload.subtype}'
msg = f'No codec entry found for {payload.blockType}'
LOGGER.debug(msg, exc_info=True)
raise exceptions.EncodeException(msg)

Expand All @@ -169,19 +152,17 @@ def decode_payload(self,
filter_values: bool | None = None,
) -> DecodedPayload:
try:
if payload.blockType == DEPRECATED_TYPE_INT:
content_bytes = b64decode(payload.content)
content = {'actualId': int.from_bytes(content_bytes, 'little')}
if payload.blockType == lookup.BlockType.Value('Deprecated'):
return DecodedPayload(
blockId=payload.blockId,
blockType=DEPRECATED_TYPE_STR,
content=content
blockType='Deprecated',
name=payload.name,
content={'bytes': payload.content},
)

# First, try to find an object lookup
impl = next((v for v in lookup.CV_OBJECTS.get()
if payload.blockType in [v.type_str, v.type_int]
and payload.subtype in [v.subtype_str, v.subtype_int]), None)
if payload.blockType in [v.type_str, v.type_int]), None)

if impl:
# We have an object lookup, and can decode the content
Expand All @@ -196,7 +177,7 @@ def decode_payload(self,
decoded = DecodedPayload(
blockId=payload.blockId,
blockType=impl.type_str,
subtype=impl.subtype_str,
name=payload.name,
content=content,
maskMode=payload.maskMode,
maskFields=payload.maskFields
Expand All @@ -214,15 +195,17 @@ def decode_payload(self,
return DecodedPayload(
blockId=payload.blockId,
blockType=intf_impl.type_str,
name=payload.name,
)

# No lookup of any kind found
# We're decoding (returned) data, so would rather return a stub than raise an error
msg = f'No codec entry found for {payload.blockType}.{payload.subtype}'
msg = f'No codec entry found for {payload.blockType}'
LOGGER.debug(msg, exc_info=True)
return DecodedPayload(
blockId=payload.blockId,
blockType=UNKNOWN_TYPE_STR,
name=payload.name,
content={
'error': msg,
},
Expand All @@ -234,10 +217,10 @@ def decode_payload(self,
return DecodedPayload(
blockId=payload.blockId,
blockType=ERROR_TYPE_STR,
name=payload.name,
content={
'error': msg,
'blockType': payload.blockType,
'subtype': payload.subtype,
},
)

Expand All @@ -249,9 +232,6 @@ def setup():


__all__ = [
'split_type',
'join_type',

'Codec',
'setup',
'CV',
Expand Down
15 changes: 1 addition & 14 deletions brewblox_devcon_spark/codec/lookup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from contextvars import ContextVar
from dataclasses import dataclass
from typing import Generator, Optional, Type
from typing import Generator, Type

from google.protobuf.descriptor import Descriptor, FileDescriptor
from google.protobuf.internal.enum_type_wrapper import EnumTypeWrapper
Expand Down Expand Up @@ -35,8 +35,6 @@ class InterfaceLookup:
class ObjectLookup:
type_str: str
type_int: int
subtype_str: Optional[str]
subtype_int: Optional[int]
message_cls: Type[Message]


Expand All @@ -61,8 +59,6 @@ def _object_lookup_generator() -> Generator[ObjectLookup, None, None]:
yield ObjectLookup(
type_str=BlockType.Name(opts.objtype),
type_int=opts.objtype,
subtype_str=(msg_name if opts.subtype else None),
subtype_int=opts.subtype,
message_cls=msg_cls,
)

Expand All @@ -76,17 +72,8 @@ def setup():
ObjectLookup(
type_str='EdgeCase',
type_int=9001,
subtype_str=None,
subtype_int=0,
message_cls=pb2.EdgeCase_pb2.Block,
),
ObjectLookup(
type_str='EdgeCase',
type_int=9001,
subtype_str='SubCase',
subtype_int=1,
message_cls=pb2.EdgeCase_pb2.SubCase,
),
]

interfaces: list[InterfaceLookup] = [
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit b8d18d7

Please sign in to comment.