Anvil Uplink as Agents

I want to use the uplink as an agent to register some local IoT services, and if possible, determine what agents are live / dead. This involves a semi-autonomous agent which connects and is assigned an identity in the app.

I don’t see anything in the docs about enumerating connected agents, nor obvious ways to create callbacks for agent functions. Before I go traipsing about the API-side like Saruman though Fangorn, is there packaged behavior for this purpose?

Round-0 is using the server uplink. If this works, i will probably keep it permanently since it gives me some nice features.

Not sure if I understand exactly, but here goes anyway …

When you decorate a function with @anvil.server.callable you can optionally specify the name the function is published as. For example :

@anvil.server.callable("dave")
def myfunctioncalledsomethingelse():
   ...

would be called like this :

anvil.server.call("dave")

So, when your uplink service starts, generate a random name for your function and use that in your decorator. Then make sure the first thing your function does is to call a server function with that name as a parameter which adds that name to a table.

In that table you then have an enumerable list of attached uplink functions.

You can’t tell (as far as I know) when an uplink function goes away, so what I do is wrap all calls to those functions in a try...except block, and delete the table row if it fails.

Is that any help to you?

4 Likes

David,

My next step was to investigate the decorator and look for this sort of mechanism. I am fine with polling agents with try/except. You have given me a good answer for the most significant question.

Sincerely,
Joshua

2 Likes

David,

After some experimentation, I used the anvil.server.register.

  anvil.server.register(Read,  f"{agent_name}_read")
  anvil.server.register(Write,  f"{agent_name}_write")

The functions Read and Write were locals, because you cannot register class methods.

def Main(config):
    def Read(toast):
        ''' test message '''
        logger.debug(f'Read: {toast}')
        retval = agent.Read()
        return retval
           
    def Write(toast):
        ''' test message '''
        logger.debug(f'Write: {toast}')
        retval = agent.Write()
        return retval

Ooo, I don’t know how register works under the hood. I would check with Anvil Central (@meredydd, @daviesian, @shaun or @bridget) if that’s recommended or not.

I can’t find anything in the docs about it, which makes me think you can’t rely on it?

Might just be me…

I read the source. It’s pretty straight forward. I was looking for an official way, but there is none. If you look, this is what the decorator essentially does in any case.

Please don’t use that function; it’s internal and likely to go away at some point! You can accomplish the same thing using anvil.server.callable as a function:

anvil.server.callable("my_func_name")(my_func)

(This is actually what Python’s @ decorator syntax does under the hood!)

1 Like

Thank you. I have changed my code, I appreciate your answer.

I haven’t taken the time to read about decorators yet, and I couldn’t find the syntax which I needed.