omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    Correct way to call Pythonista script from within a Shortcuts workflow?

    Pythonista
    7
    38
    15615
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • mikeno
      mikeno last edited by mikeno

      Hi everybody, I could call a Pythonista script from shortcuts using url and safari but it works only if the iPad is awake, is there a way to let it work when the iPad is asleep?
      I also tried running a Pythonista script using scheduler but it works only if I stay in the Pythonista app.
      What I want to achieve is writing some info into a file every hour

      cvp 1 Reply Last reply Reply Quote 0
      • cvp
        cvp @mikeno last edited by

        @mikeno I don't know what you want to do while your IPad is asleep but Shortcuts offers automations. Perhaps that could help.

        1 Reply Last reply Reply Quote 0
        • mikeno
          mikeno last edited by mikeno

          Yes but only everyday, I want to read the value of the barometer sensor every hour, I can get this value with Pythonista. I didn’t find a way to get this information in shortcuts nor in JS (scriptable).
          I found also a way to do some tasks every hour in shortcuts but I don’t find a way to get the barometer sensor value.

          cvp 1 Reply Last reply Reply Quote 0
          • cvp
            cvp @mikeno last edited by

            @mikeno said

            I found also a way to do some tasks every hour in shortcuts

            But you could start a Pythonista script every hour?

            1 Reply Last reply Reply Quote 0
            • mikeno
              mikeno last edited by

              Yes, it works but only if the iPad is awake

              cvp 1 Reply Last reply Reply Quote 0
              • cvp
                cvp @mikeno last edited by

                @mikeno did you try to run an automation at specified time, which runs a Pythonista short script logging the pressure in a file and put your IPad asleep some time before the specified time?

                1 Reply Last reply Reply Quote 0
                • mikeno
                  mikeno last edited by

                  @cvp I’m not sure to understand what you mean, but calling a pythonista script from a shortcuts or an automation requires the iPad to be awake

                  cvp 1 Reply Last reply Reply Quote 0
                  • cvp
                    cvp @mikeno last edited by cvp

                    @mikeno ok, I thought that calling the script from the shortcut did launch Pythonista even if iPad not awake. If you have Pyto, you could test because it runs really in background like a music player

                    1 Reply Last reply Reply Quote 0
                    • mikeno
                      mikeno last edited by mikeno

                      I don’t know PyTo but I will try, thx in any case

                      cvp 1 Reply Last reply Reply Quote 0
                      • cvp
                        cvp @mikeno last edited by cvp

                        @mikeno not Py To but Pyto, I think there is a free test version

                        1 Reply Last reply Reply Quote 0
                        • mikeno
                          mikeno last edited by

                          I just downloaded it but my trial period already expired because I probably already tried it some times ago and since I don’t know if it works, I don’t want to buy it. If you’ve it, could you try if it runs when iPad is asleep?

                          cvp 2 Replies Last reply Reply Quote 0
                          • cvp
                            cvp @mikeno last edited by

                            @mikeno I'll do it and let it know

                            1 Reply Last reply Reply Quote 0
                            • cvp
                              cvp @mikeno last edited by cvp

                              @mikeno I have tried a script which prints the time each second and closed my iPad cover during 200 seconds and when I have reopened it, the script was still running

                              1 Reply Last reply Reply Quote 0
                              • mikeno
                                mikeno last edited by

                                Thx, the question is now if Pyto can read the barometer sensor value, below a short code which runs fine under Pythonista:

                                from objc_util import ObjCInstance, ObjCClass, ObjCBlock, c_void_p
                                
                                pressure = None
                                
                                def get_pressure():
                                  
                                  def handler(_cmd, _data, _error):
                                    global pressure
                                    pressure = ObjCInstance(_data).pressure()
                                
                                  handler_block = ObjCBlock(handler, restype=None, argtypes=[c_void_p, c_void_p, c_void_p])
                                
                                  CMAltimeter = ObjCClass('CMAltimeter')
                                  NSOperationQueue = ObjCClass('NSOperationQueue')
                                  if not CMAltimeter.isRelativeAltitudeAvailable():
                                    print('This device has no barometer.')
                                    return
                                  altimeter = CMAltimeter.new()
                                  main_q = NSOperationQueue.mainQueue()
                                  altimeter.startRelativeAltitudeUpdatesToQueue_withHandler_(main_q, handler_block)
                                  try:
                                    while pressure is None:
                                      pass
                                  finally:
                                    altimeter.stopRelativeAltitudeUpdates()
                                    #print('Updates stopped.')
                                    return pressure.floatValue()*10
                                
                                pressure = get_pressure()
                                print(pressure)
                                
                                cvp 2 Replies Last reply Reply Quote 0
                                • cvp
                                  cvp @mikeno last edited by cvp

                                  @mikeno I know this code but I'm new in Pyto and surely not (yet?) a specialist in ObjectiveC of Pyto.
                                  I don't not yet know how to define an ObjcBlock in Pyto but I'll try.
                                  But, obviously, I'll need some time

                                  1 Reply Last reply Reply Quote 0
                                  • cvp
                                    cvp @mikeno last edited by cvp

                                    @mikeno Sorry, no idea how to define an ObjcBlock in rubicon (ObjectiveC in Pyto).
                                    Hoping that @JonB will read this and be able to help, as usual.

                                    # coding: utf-8
                                    from rubicon.objc import *
                                    from  ctypes import *
                                    
                                    def handler(_cmd, _data, _error):
                                        print(ObjCInstance(_data))
                                    
                                    handler_block = ObjCBlock(handler, None, [c_void_p, c_void_p, c_void_p])
                                    
                                    def main():
                                        CMAltimeter = ObjCClass('CMAltimeter')
                                        NSOperationQueue = ObjCClass('NSOperationQueue')
                                        if not CMAltimeter.isRelativeAltitudeAvailable():
                                            print('This device has no barometer.')
                                            return
                                        altimeter = CMAltimeter.new()
                                        main_q = NSOperationQueue.mainQueue
                                        altimeter.startRelativeAltitudeUpdatesToQueue_withHandler_(main_q, handler_block)
                                        print('Started altitude updates.')
                                        try:
                                            while True:
                                                pass
                                        finally:
                                            altimeter.stopRelativeAltitudeUpdates()
                                            print('Updates stopped.')
                                    
                                    if __name__ == '__main__':
                                        main()
                                    

                                    Gives

                                    Traceback (most recent call last):
                                      File "iCloud/barometer.py", line 8, in <module>
                                        handler_block = ObjCBlock(handler, None, [c_void_p, c_void_p, c_void_p])
                                      File "Pyto.app/Lib/rubicon/objc/api.py", line 1834, in __init__
                                        self.struct = cast(self.pointer, POINTER(ObjCBlockStruct))
                                      File "Pyto.app/site-packages/python3.10/ctypes/__init__.py", line 510, in cast
                                        return _cast(obj, obj, typ)
                                    ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type
                                    
                                    JonB 1 Reply Last reply Reply Quote 0
                                    • mikeno
                                      mikeno last edited by

                                      Thx for trying, I’ll wait!

                                      cvp 1 Reply Last reply Reply Quote 0
                                      • JonB
                                        JonB @cvp last edited by JonB

                                        @cvp I believe in Rubicon, the preferred usage is via type annotations and decorators. Also ObjCBlock wraps ObjC blocks so they can be called in python, while Block wraps python so it is calls me in objc-- so you want plain old Block.

                                        I think the way you'd do it in Rubicon is:

                                        (Edited)

                                        @Block
                                        def handler(altitudeData: ObjCInstance, err:NSError) -> None:
                                            print(altitudeData)
                                        

                                        Or, I think you can skip the annotation on ObjCInstances:

                                        @Block
                                        def handler(altitudeData, err:NSError) -> None:
                                            print(altitudeData)
                                        
                                        cvp 1 Reply Last reply Reply Quote 0
                                        • cvp
                                          cvp @JonB last edited by cvp

                                          @JonB problems
                                          1)

                                          @Block
                                          def handler(altitudeData , err:NSError) -> None:
                                              print(altitudeData)
                                          
                                          handler_block = ObjCBlock(handler, None, [c_void_p, c_void_p])
                                          

                                          Gives

                                          Traceback (most recent call last):
                                            File "iCloud/barometer.py", line 6, in <module>
                                              def handler(altitudeData, err:NSError) -> None:
                                          NameError: name 'NSError' is not defined. Did you mean 'OSError'?
                                          
                                          @Block
                                          def handler(altitudeData, err) -> None:
                                              print(altitudeData)
                                          
                                          handler_block = ObjCBlock(handler, None, [c_void_p, c_void_p])
                                          

                                          Gives

                                          Traceback (most recent call last):
                                            File "iCloud/barometer.py", line 6, in <module>
                                              def handler(altitudeData, err) -> None:
                                            File "Pyto.app/Lib/rubicon/objc/api.py", line 1939, in __init__
                                              raise ValueError(
                                          ValueError: Function has no argument type annotation for parameter 'altitudeData' - please add one, or
                                           pass return and argument types directly into Block
                                          
                                          @Block
                                          def handler(altitudeData:ObjCInstance, err:ObjCInstance) -> None:
                                             print(altitudeData)
                                          
                                          handler_block = ObjCBlock(handler, None, [c_void_p, c_void_p])
                                          

                                          Gives

                                          Traceback (most recent call last):
                                            File "iCloud/barometer.py", line 9, in <module>
                                              handler_block = ObjCBlock(handler, None, [c_void_p, c_void_p])
                                            File "Pyto.app/Lib/rubicon/objc/api.py", line 1846, in __init__
                                              self.struct.contents.invoke.argtypes = (objc_id, ) + tuple(ctype_for_type(arg_type) for arg_type i
                                          n argtypes)
                                            File "Pyto.app/Lib/rubicon/objc/api.py", line 1846, in <genexpr>
                                              self.struct.contents.invoke.argtypes = (objc_id, ) + tuple(ctype_for_type(arg_type) for arg_type i
                                          n argtypes)
                                            File "Pyto.app/Lib/rubicon/objc/types.py", line 103, in ctype_for_type
                                              return _ctype_for_type_map.get(tp, tp)
                                          TypeError: unhashable type: 'list'
                                          
                                          @Block
                                          def handler(altitudeData:ObjCInstance, err:ObjCInstance) :#-> None:
                                              print(altitudeData)
                                          
                                          handler_block = ObjCBlock(handler, None)#, [c_void_p, c_void_p])
                                          

                                          Gives

                                          Traceback (most recent call last):
                                            File "iCloud/barometer.py", line 6, in <module>
                                              def handler(altitudeData:ObjCInstance, err:ObjCInstance) :#-> None:
                                            File "Pyto.app/Lib/rubicon/objc/api.py", line 1930, in __init__
                                              raise ValueError(
                                          ValueError: Function has no return type annotation - please add one, or pass return and argument types
                                           directly into Block
                                          Traceback (most recent call last):
                                            File "iCloud/barometer.py", line 6, in <module>
                                              def handler(altitudeData:ObjCInstance, err:ObjCInstance) :#-> None:
                                            File "Pyto.app/Lib/rubicon/objc/api.py", line 1930, in __init__
                                              raise ValueError(
                                          ValueError: Function has no return type annotation - please add one, or pass return and argument types
                                           directly into Block
                                          
                                          @Block
                                          def handler(altitudeData:ObjCInstance, err:ObjCInstance) -> None:
                                              print(altitudeData)
                                              
                                          handler_block = ObjCBlock(handler, None, (c_void_p, c_void_p))
                                          

                                          Gives

                                          Traceback (most recent call last):
                                            File "iCloud/barometer.py", line 10, in <module>
                                              handler_block = ObjCBlock(handler, None, (c_void_p, c_void_p))
                                            File "Pyto.app/Lib/rubicon/objc/api.py", line 1846, in __init__
                                              self.struct.contents.invoke.argtypes = (objc_id, ) + tuple(ctype_for_type(arg_type) for arg_type i
                                          n argtypes)
                                          TypeError: item 2 in _argtypes_ has no from_param method
                                          
                                          E 1 Reply Last reply Reply Quote 0
                                          • bosco
                                            bosco last edited by bosco

                                            @mikeno This code works for me with the latest version of pyto.

                                            # coding: utf-8
                                            from rubicon.objc import Block, ObjCClass, ObjCInstance, py_from_ns
                                            from rubicon.objc.runtime import objc_id
                                            
                                            pressure = None
                                            
                                            def handler(_data) -> None:
                                                nspressure = ObjCInstance(_data).pressure
                                                global pressure
                                                pressure = py_from_ns(nspressure)
                                            
                                            handler_block = Block(handler, None, (objc_id))
                                            
                                            def get_pressure():
                                                CMAltimeter = ObjCClass('CMAltimeter')
                                                NSOperationQueue = ObjCClass('NSOperationQueue')
                                                if not CMAltimeter.isRelativeAltitudeAvailable():
                                                    print('This device has no barometer.')
                                                    return
                                                altimeter = CMAltimeter.new()
                                                main_q = NSOperationQueue.mainQueue
                                                altimeter.startRelativeAltitudeUpdatesToQueue_withHandler_(main_q, handler_block)
                                                print('Started altitude updates.')
                                                try:
                                                    while pressure is None:
                                                        pass
                                                finally:
                                                    altimeter.stopRelativeAltitudeUpdates()
                                                    print('Updates stopped.')
                                                    return pressure
                                            
                                            if __name__ == '__main__':
                                                result = get_pressure()
                                                print(result)
                                                del pressure
                                            cvp 1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            Powered by NodeBB Forums | Contributors