partofthething / infopanel

Show live data, animations, pictures, or anything on simple displays like RGB matrices
https://partofthething.com/infopanel/
GNU General Public License v3.0
31 stars 12 forks source link

Programmatically build DynamicText sprites within a custom scene #27

Open chadjmorgan opened 2 years ago

chadjmorgan commented 2 years ago

I am trying to programmatically create dynamic text sprites within a custom scene. I am building the sprite like this:

text_1 = sprites.DynamicFancyText(width, height, data_source=None) text_1.x = 30 text_1.y = 9 text_1.apply_config({'data_label': 'text_one'}) self.sprites.append(text_1)

for some reason, the text is not updating via MQTT when the topic is updated. Dynamic text built within the config file updates fine, it's just the dynamic text I programmatically build within the custom scene.

I think maybe it has something to do with no data_source being sent to the sprite?

Any ideas? :)

chadjmorgan commented 2 years ago

To add a little context to what I am trying to do...

I am adding a dart scoreboard to this, to score games of cricket.

I have built a couple custom sprites. One to draw the actual scoreboard (all static):

class DartScoreBoard(Sprite):

    def __init__(self, max_x, max_y, data_source=None):
        """Construct a sprite."""
        Sprite.__init__(self, max_x, max_y, data_source)
        self.pallete = {1: (255, 255, 255), 2: (0, 102, 51), 3: (255, 0, 0)}
        self.frames = [
            [
                [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
                [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
                [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
                [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
                [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
                [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
                [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
                [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
                [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
                [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
            ],
        ]

The other custom sprite is the scoring marks, which are triggered via MQTT. If 1 is received, its a single. If 2 is received score a double. And if 3 is received, close out the number.

class DartScore(Sprite):

    def __init__(self, max_x, max_y, data_source):
        """Construct a sprite."""
        Sprite.__init__(self, max_x, max_y, data_source=data_source)
        self.last_val = None

    def apply_config(self, conf):
        """Validate and apply configuration to this sprite."""
        conf = Sprite.apply_config(self, conf)
        if conf["data_label"]:
            # make this a callable function to enable live/updating data
            self.value = lambda: self._convert_data(
                self.data_source[conf["data_label"]]
            )
        self._make_frames()
        return conf

    def _convert_data(self, val):
        try:
            return int(val)
        except ValueError:
            return None

    def _make_frames(self):
        """Draw requested scoring mark."""
        val = (self.value() if callable(self.value) else self.value)
        if val == 1:
            self.frames = [
              [
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,1,0,0,0],
                  [0,0,0,0,0,0,0,0,1,0,0,0,0],
                  [0,0,0,0,0,0,0,1,0,0,0,0,0],
                  [0,0,0,0,0,0,1,0,0,0,0,0,0],
                  [0,0,0,0,0,1,0,0,0,0,0,0,0],
                  [0,0,0,0,1,0,0,0,0,0,0,0,0],
                  [0,0,0,1,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
              ],
            ]
        elif val == 2:
            self.frames = [
              [
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,1,0,0,0,0,0,1,0,0,0],
                  [0,0,0,0,1,0,0,0,1,0,0,0,0],
                  [0,0,0,0,0,1,0,1,0,0,0,0,0],
                  [0,0,0,0,0,0,1,0,0,0,0,0,0],
                  [0,0,0,0,0,1,0,1,0,0,0,0,0],
                  [0,0,0,0,1,0,0,0,1,0,0,0,0],
                  [0,0,0,1,0,0,0,0,0,1,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
              ],
            ]
        elif val == 3:
            self.frames = [
              [
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,1,1,1,1,1,0,0,0,0],
                  [0,0,0,1,0,0,0,0,0,1,0,0,0],
                  [0,0,1,0,1,0,0,0,1,0,1,0,0],
                  [0,0,1,0,0,1,0,1,0,0,1,0,0],
                  [0,0,1,0,0,0,1,0,0,0,1,0,0],
                  [0,0,1,0,0,1,0,1,0,0,1,0,0],
                  [0,0,1,0,1,0,0,0,1,0,1,0,0],
                  [0,0,0,1,0,0,0,0,0,1,0,0,0],
                  [0,0,0,0,1,1,1,1,1,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
              ],
            ]
        else:
            self.frames = [
              [
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
                  [0,0,0,0,0,0,0,0,0,0,0,0,0],
              ],
            ]

        self.last_val = val

    def update_value(self):
        """Update, but only if the value has changed."""
        val = self.value() if callable(self.value) else self.value
        if val != self.last_val:
            self._make_frames()

    def render(self, display):
        self.update_value()
        Sprite._render_frame(self, display)

So for each number for each player, I need to add this DartScore sprite to the dartboard scene. If I add all 14 of these to the scene in the config yaml file (messy) it works with MQTT when I send the score (1, 2 or 3). The score is marked on the board.

I am trying to clean it up and build the scene automatically, with the 14 dynamic scoring parts programmatically added to the scene. This is what I have right now:

class Darts(Scene):
    """Builds a dart scoreboard, uses MQTT to update scores."""

    def __init__(self, width, height):
        """Construct a scene."""
        Scene.__init__(self, width, height)

        # draw scoreboard layout
        score_board = sprites.DartScoreBoard(width, height)
        self.sprites.append(score_board)

        the_title = sprites.FancyText(width, height)
        the_title.pallete = {'text': (255, 0, 0)}
        the_title.text = 'Cricket'
        the_title.x = 2
        the_title.y = 7
        self.sprites.append(the_title)

        counter = 14
        x_pos = 33

        # print scoreboard scoring header
        for i in range(7):
            new_sprite = sprites.FancyText(width, height)
            if counter == 14:
                new_sprite.text = 'BL'
            else:
                new_sprite.text = str(counter)
            new_sprite.pallete = {'text': (0, 0, 0)}
            new_sprite.x = x_pos
            new_sprite.y = 7
            self.sprites.append(new_sprite)
            counter += 1
            x_pos += 14

        for sprite in self.sprites:
            sprite.apply_config({'font_name': 'default.bdf'})

        # build dynamic areas for each player where scoring will be kept (this needs to be done programatically)
        player_one_bull = sprites.DartScore(width, height, data_source=None)
        player_one_bull.x = 30
        player_one_bull.y = 9
        player_one_bull.apply_config({'data_label': 'p1_bull'})
        self.sprites.append(player_one_bull)

The dynamic areas part (the last part) will not update now when I send the MQTT commands. I am not sure if I am not setting the data_label right, or the fact that there is no data_source being sent when building the sprite. I have been banging my head against the wall for a few hours trying to figure out why this isn't working. Any help or thoughts would be much appreciated! Thanks for making this great piece of software! I am adding a bunch of functionality to it, I will be making some pull requests if you end up wanting to add the code!

chadjmorgan commented 2 years ago

Sorry for blowing up your issue tracker lol

So, I got this working however I am not sure it is the best way to do it.

I modified the driver to pass the data_src variable to the scene_factory, like how it is passed to the sprite factory (line 7 below).

def driver_factory(disp, data_src, conf):
    """Build factory and add scenes and sprites."""
    driver = Driver(disp, data_src)
    driver.update_weather()
    driver.sprites = sprites.sprite_factory(conf["sprites"], data_src, disp)
    driver.scenes = scenes.scene_factory(
        disp.width, disp.height, conf["scenes"], driver.sprites, data_src
    )
    driver.init_modes(conf)
    return driver

Then, I modified the scene_factory to accept the variable and pass it on when the scenes are built (changed lines below are 2, 5 & 19):

def scene_factory(
    width, height, conf, existing_sprites, data_source
):  # pylint: disable=too-many-locals
    """Build scenes from config."""
    scenes = {SCENE_BLANK: Blank(width, height, data_source)}  # alway add blank scene for suspend
    cls = None
    for name, scene_data in conf.items():  # pylint: disable=too-many-nested-blocks
        for cls_name, cls in inspect.getmembers(sys.modules[__name__]):
            if scene_data["type"] == cls_name:
                break
        else:
            raise ValueError("{} is invalid active_scene".format(name))
        del scene_data["type"]
        if "sprites" in scene_data:
            sprites_to_add = scene_data.pop("sprites")
        else:
            sprites_to_add = []
        LOG.debug("Initializing %s", cls)
        scene = cls(width, height, data_source, **scene_data)
        for sprite_data in sprites_to_add:
            for spritename, spriteparams in sprite_data.items():  # should be only one
                # each active_scene gets independent copies of the sprites because scenes
                # can set different custom config for each sprite (location,
                # direction, color...)
                sprite = copy.copy(existing_sprites[spritename][0])
                existing_sprites[spritename].append(sprite)  # track the copies by name
                if spriteparams is not None:
                    for param, val in spriteparams.items():
                        if not hasattr(sprite, param):
                            raise ValueError(
                                "Invalid sprite parameter for {}: {}"
                                "".format(sprite, param)
                            )
                        setattr(sprite, param, val)
            scene.sprites.append(sprite)

        scene.apply_config(conf, existing_sprites)

        scenes[name] = scene
    return scenes

Now the Scene object needs to accept the new data source parameter (modified lines below are 4 & 9):

class Scene(object):
    """A single screen's worth of sprites."""

    def __init__(self, width, height, data_source):
        """Construct a scene."""
        self.width = width
        self.height = height
        self.sprites = []
        self.data_source = data_source

    def draw_frame(self, display):
        """Render all sprites in this scene to display."""
        for sprite in self.sprites:
            sprite.render(display)

    def apply_config(self, conf, existing_sprites):
        """Apply optional extra config."""

    def reinit(self):
        """Reinitialize when scene comes back up on the screen."""
        for sprite in self.sprites:
            sprite.reinit()

Finally, my Darts scene can have access to the data source and pass it to the DartScore sprite (modified lines below are 4, 6 & 40):

class Darts(Scene):
    """Builds a dart scoreboard, uses MQTT to update scores."""

    def __init__(self, width, height, data_source):
        """Construct a scene."""
        Scene.__init__(self, width, height, data_source=data_source)

        # draw scoreboard layout
        score_board = sprites.DartScoreBoard(width, height)
        self.sprites.append(score_board)

        the_title = sprites.FancyText(width, height)
        the_title.pallete = {'text': (255, 0, 0)}
        the_title.text = 'Cricket'
        the_title.x = 2
        the_title.y = 7
        self.sprites.append(the_title)

        counter = 14
        x_pos = 33

        # print scoreboard scoring header
        for i in range(7):
            new_sprite = sprites.FancyText(width, height)
            if counter == 14:
                new_sprite.text = 'BL'
            else:
                new_sprite.text = str(counter)
            new_sprite.pallete = {'text': (0, 0, 0)}
            new_sprite.x = x_pos
            new_sprite.y = 7
            self.sprites.append(new_sprite)
            counter += 1
            x_pos += 14

        for sprite in self.sprites:
            sprite.apply_config({'font_name': 'default.bdf'})

        # build dynamic areas for each player where scoring will be kept (this needs to be done programatically)
        player_one_bull = sprites.DartScore(width, height, self.data_source)
        player_one_bull.x = 30
        player_one_bull.y = 9
        player_one_bull.apply_config({'data_label': 'p1_bull'})
        self.sprites.append(player_one_bull)

Let me know if you think there is a better way to do this, or maybe the data source is already available to the Scene object and I am just missing something.

partofthething commented 2 years ago

This is a very cool application and I'm excited you're working on it. Sorry for the struggles and slow response on my end.

In your 2nd comment, it looks like your DartScore is perfect but yeah the data_source has to be the same data source that the system connects to the MQTT listener, so the data_source=None there is disconnecting those. In your 3rd comment, I see you realized that and adjusted the init system to make the data source available to the scenes during init.

Honestly, I like how you've handled it. It is more consistent, as you say, since sprites were already getting the data source. You are not missing anything. An alternate approach would require setting some kind of global variable to have a data source, but I like your approach much better.

If you want, I'd definitely be interested in accepting this as a pull request.