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.


    Pythonista 1.6 Beta

    Pythonista
    55
    301
    473828
    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.
    • wradcliffe
      wradcliffe last edited by

      I was able to use the Bluetooth LE module to talk to a LightBlue Bean and enumerate all of its services and characteristics.

      I also tried reading all the values for each characteristic and ran into one problem. The values returned may or may not be text strings and if you simply assume they are and print them to the console you can get the module to throw an exception

      TypeError: must be string without null bytes, not str

      Trace back says it happened at line 73 in cb.py

      After that you can recover but you can also crash completely or leave the module in a bad state and unable to talk to the peripheral.

      Here is my code:

      import cb
      import sound
      import time
      import struct
      
      class LightBlueBean (object):
      	def __init__(self):
      		self.peripheral = None
      
      	def did_discover_peripheral(self, p):
      		print 'Discovered:', p.name
      		if p.name and 'Bean' in p.name and not self.peripheral:
      			self.peripheral = p
      			print 'Connecting to Bean...'
      			cb.connect_peripheral(p)
      
      	def did_connect_peripheral(self, p):
      		print 'Connected:', p.name
      		print 'Discovering services...'
      		p.discover_services()
      
      	def did_fail_to_connect_peripheral(self, p, error):
      		print 'Failed to connect: %s' % (error,)
      
      	def did_disconnect_peripheral(self, p, error):
      		print 'Disconnected, error: %s' % (error,)
      		self.peripheral = None
      
      	def did_discover_services(self, p, error):
      		print 'Did discover services...'
      		for s in p.services:
      			print 'Service:', s.uuid
      			if True: # s.uuid == '180D'
      				print 'Discovering characteristics...'
      				p.discover_characteristics(s)
      
      	def did_discover_characteristics(self, s, error):
      		print 'Did discover characteristics...'
      		for c in s.characteristics:
      			print 'Characteristic:', c.uuid, ' Value:', c.value
      			#if c.uuid == '2A37':
      			#	self.peripheral.set_notify_value(c, True)
      			self.peripheral.read_characteristic_value(c)
      
      	def did_update_value(self, c, error):
      		#somevalue = struct.unpack('<B', c.value[1])[0]
      		#self.values.append(somevalue)
      		#print 'Value: %i' % somevalue
      		print 'Update to a value...'
      		print 'Characteristic:', c.uuid, ' Value:', c.value
      
      mngr = LightBlueBean()
      cb.set_central_delegate(mngr)
      print 'Scanning for peripherals...'
      cb.scan_for_peripherals()
      
      try:
      	while True: pass
      except KeyboardInterrupt:
      	print 'keyboard interrupt - resetting'
      	cb.reset()
      

      Here is the console output:

      Scanning for peripherals...
      Discovered: Bean
      Connecting to Bean...
      Connected: Bean
      Discovering services...
      Disconnected, error: (10, u'The connection has failed unexpectedly.')
      keyboard interrupt - resetting
      Scanning for peripherals...
      Discovered: Bean
      Connecting to Bean...
      Connected: Bean
      Discovering services...
      Did discover services...
      Service: F000FFC0-0451-4000-B000-000000000000
      Discovering characteristics...
      Service: 180A
      Discovering characteristics...
      Service: A495FF10-C5B1-4B44-B512-1370F02D74DE
      Discovering characteristics...
      Service: A495FF20-C5B1-4B44-B512-1370F02D74DE
      Discovering characteristics...
      Service: 180F
      Discovering characteristics...
      Did discover characteristics...
      Characteristic: F000FFC1-0451-4000-B000-000000000000  Value: None
      Characteristic: F000FFC2-0451-4000-B000-000000000000  Value: None
      Did discover characteristics...
      Characteristic: 2A23  Value: None
      Characteristic: 2A24  Value: None
      Characteristic: 2A25  Value: None
      Characteristic: 2A26  Value: None
      Characteristic: 2A27  Value: None
      Characteristic: 2A28  Value: None
      Characteristic: 2A29  Value: None
      Characteristic: 2A2A  Value: None
      Characteristic: 2A50  Value: None
      Did discover characteristics...
      Characteristic: A495FF11-C5B1-4B44-B512-1370F02D74DE  Value: None
      Did discover characteristics...
      Characteristic: A495FF21-C5B1-4B44-B512-1370F02D74DE  Value: None
      Characteristic: A495FF22-C5B1-4B44-B512-1370F02D74DE  Value: None
      Characteristic: A495FF23-C5B1-4B44-B512-1370F02D74DE  Value: None
      Characteristic: A495FF24-C5B1-4B44-B512-1370F02D74DE  Value: None
      Characteristic: A495FF25-C5B1-4B44-B512-1370F02D74DE  Value: None
      Did discover characteristics...
      Characteristic: 2A19  Value: None
      Update to a value...
      Characteristic: F000FFC1-0451-4000-B000-000000000000  Value: None
      Update to a value...
      Characteristic: F000FFC2-0451-4000-B000-000000000000  Value: None
      Update to a value...
      Characteristic: 2A23  Value: Update to a value...
      Characteristic: 2A24  Value: Bean
      Update to a value...
      Characteristic: 2A25  Value: Serial Number
      Update to a value...
      Characteristic: 2A26  Value: 201409080001 Img-B
      Update to a value...
      Characteristic: 2A27  Value: E
      Update to a value...
      Characteristic: 2A28  Value: Software Revision
      Update to a value...
      Characteristic: 2A29  Value: Punch Through Design
      Update to a value...
      Characteristic: 2A2A  Value: Update to a value...
      Characteristic: 2A50  Value: Update to a value...
      Characteristic: A495FF11-C5B1-4B44-B512-1370F02D74DE  Value: Update to a value...
      Characteristic: A495FF21-C5B1-4B44-B512-1370F02D74DE  Value: 
      Update to a value...
      Characteristic: A495FF22-C5B1-4B44-B512-1370F02D74DE  Value: 
      Update to a value...
      Characteristic: A495FF23-C5B1-4B44-B512-1370F02D74DE  Value: 
      Update to a value...
      Characteristic: A495FF24-C5B1-4B44-B512-1370F02D74DE  Value: 
      Update to a value...
      Characteristic: A495FF25-C5B1-4B44-B512-1370F02D74DE  Value: 
      Update to a value...
      Characteristic: 2A19  Value: 1
      keyboard interrupt - resetting
      
      1 Reply Last reply Reply Quote 0
      • dgelessus
        dgelessus last edited by

        Instead of a plain print(data), try using print(data.replace("\x00", "")), with data being the value received from the peripheral. This simply removes any null bytes from the string to stop print from complaining. For debugging purposes you might want to replace null bytes with something like "NULL" so you can find them in the printed text.

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

          Is it new in this version that the various console.alert "types" now return the button number (as an int)? It broke a couple of my scipts...

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

            @wradcliffe

            Most strings you're dealing with will probably be binary data, so I'd recommend encoding them as hex before printing (print c.value.encode('hex')). Nevertheless, there are definitely some stability issues when you encounter exceptions in any of the callbacks. I might change this to disconnect when an exception is thrown in a callback, which might make it more likely to recover successfully.

            @hyshai

            Is it new in this version that the various console.alert "types" now return the button number (as an int)? It broke a couple of my scipts...

            The standard alert() function always did this, but I assume you're referring to other alert types? There are definitely some bugs with those right now, looking into it.

            @the_buch

            for reminders.get_reminders(completed=TRUE) is there currently, or could there be in a future version, a way to filter completed reminders with completion date.

            Right now, it's not possible, but I will at the very least add a completion_date attribute to the Reminder class, so you could filter them manually.

            @Moe

            I assume the appex module you teased on Twitter is not integrated/activated in this Beta?

            No, this won't be in 1.6.

            @dgelessus

            The Pythonista.app bundle is now fully moved out of the "Data" folder and no longer easily accessible (sad face)

            That's an iOS 8 thing, nothing I can do about it, though it is still accessible if you have the correct path. Right now, you could do this with scene.get_image_path (which will return a path that is within the app bundle, you'd have to walk up the hierarchy a bit to get the root directory of the app).

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

              @the_buch

              Also would like to see this module in Editorial eventually. Better than using url schemes in all these reminder workflows.

              Yes, the reminders module will definitely be in the next update of Editorial as well, same goes for twitter and probably dialogs. I don't plan to integrate cb in Editorial though.

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

                I have been working with the dialogs form_dialog and this test code:

                import dialogs
                import datetime
                
                dt = datetime.datetime.now()
                fields = [
                  {'key' : 'the_key0', 'type' : 'switch', 'value' : 'the_value'},
                  {'key' : 'the_key1', 'type' : 'text', 'value' : 'the_value'},
                  {'key' : 'the_key2', 'type' : 'url', 'value' : 'the_value'},
                  {'key' : 'the_key3', 'type' : 'email', 'value' : 'the_value'},
                  {'key' : 'the_key4', 'type' : 'password', 'value' : 'the_value'},
                  {'key' : 'the_key5', 'type' : 'number', 'value' : '100' },
                  {'key' : 'the_key6', 'type' : 'check', 'value' : 'the_value'},
                  {'key' : 'the_key7', 'type' : 'datetime', 'value' : dt},
                  {'key' : 'the_key8', 'type' : 'date', 'value' : dt},
                  {'key' : 'the_key9', 'type' : 'time', 'value' : dt}
                ]
                result=dialogs.form_dialog(title='look at all this stuff', fields=fields)
                print 'text:', result
                
                

                When I look at this, I can't help thinking that all the field data should be aligned right and that there should be labels on each one. Should there be a 'label' key added? How is the user suppose to know what each field represents?

                I suppose you could use sections to implement labels, but that seems wrong. Section as a way of breaking up and labeling combinations of like fields is good.

                sections = [
                  ('switch section', [{'key' : 'the_key0', 'type' : 'switch', 'value' : 'the_value'}]),
                  ('text section', [{'key' : 'the_key1', 'type' : 'text', 'value' : 'the_value'}])
                ]
                result=dialogs.form_dialog(title='look at all this stuff', sections=sections)
                print 'text:', result
                

                Also - datetime requires/returns a datetime and date and time do as well. Should date and time require and return date and time objects?

                Also, Also - email, url, number don't seem to do anything different then text. Shouldn't they be enforcing formatting or something?

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

                  How is the user suppose to know what each field represents?

                  There's a 'title' key you can use, the documentation is a little incomplete right now with regards to the supported keys.

                  Also - datetime requires/returns a datetime and date and time do as well. Should date and time require and return date and time objects?

                  Maybe, it was a bit easier to implement this way, and you can easily convert it to a date or time object by calling datetime.date() or datetime.time().

                  Also, Also - email, url, number don't seem to do anything different then text. Shouldn't they be enforcing formatting or something?

                  The keyboard for URL and email fields is different (e.g. the email keyboard has an additional '@' key), and they have autocorrection disabled by default.

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

                    text = dialogs.text_dialog(title='Name Your Reminder', autocapitalization=ui.AUTOCAPITALIZE_SENTENCES, spellchecking=None)
                    r = reminders.Reminder()
                    r.title = text
                    r.save()

                    Gives me a excepted string error.

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

                      @techteej Did you use the Done button in the text dialog? If you cancel the dialog (via 'x'), it'll return None.

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

                        It shows up while the dialog is up

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

                          @techteej Is that really your entire code?

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

                            There's a 'title' key you can use ...

                            The title key works perfectly. I noticed that the text color defaults to black except for the checkbox case where it is blue (or same as check color).

                            Looking forward to more keys assuming now that you are going to have color, font, etc. to really allow full control.

                            What about field validation? Popping up a special keyboard is nice, but a delegate function called on each keystroke would nail it. I used to work on named entity extraction in text and you can do a lot with simple regex matching, but you need to run code to do credit card numbers (for the checksum). I think mapping field types to entities would be super cool.

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

                              @omz Here is my entire code.

                              # coding: utf-8
                              import dialogs
                              import reminders
                              import ui
                              
                              class Data (ui.ListDataSource):
                              	def __init__(self, items=None):
                              		ui.ListDataSource.__init__(self, items)
                              
                              	def tableview_cell_for_row(self, tableview, section, row):
                              		cell = ui.TableViewCell()
                              		cell.text_label.text = str(self.items[row])
                              		return cell
                              
                              v = ui.load_view('reminders')
                              
                              def button_action(sender):
                              	if segment.selected_index == 0:
                              		todo = reminders.get_reminders(completed=False)
                              		for r in todo:
                              			full = r.title
                              			reminders_table.data_source = Data(items=[full])
                              			reminders_table.reload()
                              	elif segment.selected_index == 1:
                              		done = reminders.get_reminders(completed=True)
                              		for r in done:
                              			full = r.title
                              			reminders_table.data_source = Data(items=[full])
                              			reminders_table.reload()
                              
                              def but_action(sender):
                              	text = dialogs.text_dialog(title='Name Your Reminder', autocapitalization=ui.AUTOCAPITALIZE_SENTENCES, spellchecking=None)
                              	r = reminders.Reminder()
                              	r.title = text
                              	r.save()
                              
                              segment = v['segmentedcontrol1']
                              segment.action = button_action
                              reminders_table = v['reminders']
                              
                              create_button = ui.ButtonItem()
                              create_button.image = ui.Image.named('ionicons-ios7-plus-empty-32')
                              create_button.action = but_action
                              
                              v.right_button_items = [create_button]
                              v.present('sheet')
                              
                              1 Reply Last reply Reply Quote 0
                              • omz
                                omz last edited by

                                @techteej Similar to console alerts, dialogs don't work from the main UI thread (allowing this would essentially lead to a deadlock). Try decorating your but_action function with @ui.in_background.

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

                                  Found a bug. In the UI Editor when delete enabled is off, you can still delete rows in a table.

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

                                    Will dialogs allow me to create tables with cells (rows and columns)?

                                    This would be most useful, otherwise I don't see an advantage to dialogs over UI.

                                    Pinch to zoom in the UI editor would be nice too, as well as saving UI control presets.

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

                                      The beta doesn't seem to ask for permission to use Location Services when using the location module for the first time.

                                      I thought it might be for all required permissions, but the Reminders seems to work fine.

                                      Anyone have any ideas on this?

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

                                        Found a bug. In the UI Editor when delete enabled is off, you can still delete rows in a table.

                                        I can't reproduce this. Note however that the "delete enabled" attribute only applies to the default ListDataSource that gets created as a convenience when loading a TableView from a pyui file. If you set a different data source after loading the view, it doesn't have an effect.

                                        Will dialogs allow me to create tables with cells (rows and columns)?
                                        This would be most useful, otherwise I don't see an advantage to dialogs over UI.

                                        No. For the most part, dialogs doesn't really let you do things you couldn't do with the ui module, but things like form_dialog would require a lot more code when done with ui directly. There are also some things that you couldn't do otherwise, like dialogs.import_file() or dialogs.share().

                                        The beta doesn't seem to ask for permission to use Location Services when using the location module for the first time.

                                        Are you sure that you didn't give permission with the previous version? The beta would inherit those permissions (it's the same app after all).

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

                                          I uninstalled the beta, installed the current App Store version and ran a simple get location script. It prompted for Location permissions and retrieved my location.

                                          I then uninstalled the App Store version, installed the beta again and ran the script.

                                          The script prints out the value of location.get_location(). It is currently printing out None in the beta with no prompt to allow access to Location Services.

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

                                            Bluetooth LE? Bless you! I'd love to beta test that. Sending email as soon as I track down your email address ;-)

                                            -steve (aka zencuke)

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            Powered by NodeBB Forums | Contributors