<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dw="https://www.dreamwidth.org">
  <id>tag:dreamwidth.org,2009-04-20:105601</id>
  <title>Busy hands | Disquiet mind</title>
  <subtitle>Craft and Tech Notebook</subtitle>
  <author>
    <name>chebe</name>
  </author>
  <link rel="alternate" type="text/html" href="https://chebe.dreamwidth.org/"/>
  <link rel="self" type="text/xml" href="https://chebe.dreamwidth.org/data/atom"/>
  <updated>2022-11-04T18:05:51Z</updated>
  <dw:journal username="chebe" type="personal"/>
  <entry>
    <id>tag:dreamwidth.org,2009-04-20:105601:126547</id>
    <link rel="alternate" type="text/html" href="https://chebe.dreamwidth.org/126547.html"/>
    <link rel="self" type="text/xml" href="https://chebe.dreamwidth.org/data/atom/?itemid=126547"/>
    <title>PicoPlanet Video Call Controller</title>
    <published>2021-03-24T21:14:52Z</published>
    <updated>2022-11-04T18:05:51Z</updated>
    <category term="pla"/>
    <category term="3dprinting"/>
    <category term="python"/>
    <category term="photos"/>
    <category term="code"/>
    <category term="picoplanet"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">A while back I picked up a very cute circuit python board with procedurally generated graphics called the &lt;a href="https://www.tindie.com/products/bleeptrack/picoplanet/"&gt;PicoPlanet&lt;/a&gt;. (I got design number 12.) A few months into the Pandemic, a bunch of projects around making video calls easier to use appeared. Adafruit even has one for circuit python; a &lt;a href="https://learn.adafruit.com/PyRulerVideoPanic/code"&gt;video call panic button, for PyRuler&lt;/a&gt;. I found their setup, which mutes audio and turns off video at the same time, didn't work for me. Mostly because the controls in these apps are mostly toggles. So if I had my video on, but microphone off, and I hit that button, I'd be turning off my camera but turning on my microphone. Instead I broke the controls down to;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;button one un/mutes my microphone, in all my most common applications,&lt;/li&gt;&lt;br /&gt;&lt;li&gt;button two turns on/off my camera, in all my most common applications,&lt;/li&gt;&lt;br /&gt;&lt;li&gt;button three un/mutes the speakers on my computer.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://chebe.dreamwidth.org/126547.html#cutid1"&gt;Code&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Which works great (for Zoom and Discord, Skype is experimental), but the board dangling at the end of a USB cable isn't the easiest to grab. So when I &lt;a href="https://chebe.dreamwidth.org/126073.html"&gt;got a 3D printer&lt;/a&gt; the first thing I printed was a case.&lt;br /&gt;&lt;br /&gt;The PicoPlanet &lt;a href="https://github.com/bleeptrack/picoplanet"&gt;github&lt;/a&gt; contains a two-piece &lt;a href="https://github.com/bleeptrack/picoplanet/tree/master/frameCase"&gt;frame case&lt;/a&gt;, and a link to a &lt;a href="https://www.thingiverse.com/thing:4583005"&gt;bumper case&lt;/a&gt;. I went with the bumper case because I didn't want to obscure the design. I printed the closed back version, and it was a snug fit, with some gentle hammering to get it in flat. But it definitely makes it easier to grab.&lt;br /&gt;&lt;br /&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___2" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://chebe.dreamwidth.org/126547.html#cutid2"&gt;Photo&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___2" aria-live="assertive"&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p class="image" style="text-align:center;"&gt;&lt;a href="https://lostaurora.net/gallery/galleries/blog2021/20210317_picoPlanet_01_assembled.JPG"&gt;&lt;img width="648" alt="" src="https://lostaurora.net/gallery/galleries/blog2021/20210317_picoPlanet_01_assembled.JPG" height="348" border="0"&gt;&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Closed bumper case on PicoPlanet (design #12)&lt;/strong&gt;&lt;br /&gt;&lt;em&gt;Photo by &lt;span style='white-space: nowrap;'&gt;&lt;a href='https://chebe.dreamwidth.org/profile'&gt;&lt;img src='https://www.dreamwidth.org/img/silk/identity/user.png' alt='[personal profile] ' width='17' height='17' style='vertical-align: text-bottom; border: 0; padding-right: 1px;' /&gt;&lt;/a&gt;&lt;a href='https://chebe.dreamwidth.org/'&gt;&lt;b&gt;chebe&lt;/b&gt;&lt;/a&gt;&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=chebe&amp;ditemid=126547" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-04-20:105601:125117</id>
    <link rel="alternate" type="text/html" href="https://chebe.dreamwidth.org/125117.html"/>
    <link rel="self" type="text/xml" href="https://chebe.dreamwidth.org/data/atom/?itemid=125117"/>
    <title>Deleting twitter DMs</title>
    <published>2020-12-07T20:08:36Z</published>
    <updated>2020-12-07T20:30:55Z</updated>
    <category term="code"/>
    <category term="twitter"/>
    <category term="python"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">I wanted to delete my DMs on twitter. (Just because seeing things makes me remember things about them, and it's plenty crowded in this head already.) I saw you can delete (your copy) of DMs, but only message-by-message. I tried to find 3rd party tools to do it for me, and they have all stopped existing and/or working. So, I hit up the API.&lt;br /&gt;&lt;br /&gt;It turns out versions are crucially important. I'm using python3, tweepy 3.9.0, and twitter API 1.1.&lt;br /&gt;&lt;br /&gt;Following on from &lt;a href="https://chebe.dreamwidth.org/121807.html"&gt;my previous adventures&lt;/a&gt; I had to add 'Direct Messages' permission to my app and regenerate the keys.&lt;br /&gt;&lt;br /&gt;Actually deleting the DM is the easy part;&lt;br /&gt;&lt;code&gt;api.destroy_direct_message(direct_message.id)&lt;/code&gt;&lt;br /&gt;(Just remember you are only deleting your copy of the messages.)&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Finding&lt;/strong&gt; the message/id to delete is the hard bit. The best &lt;a href="http://docs.tweepy.org/en/latest/api.html#direct-message-methods"&gt;available&lt;/a&gt; is &lt;code&gt;list_direct_messages&lt;/code&gt; which lists both sent and received direct messages, but only in the last 30 days. It uses &lt;a href="http://docs.tweepy.org/en/latest/cursor_tutorial.html"&gt;cursors&lt;/a&gt; for paging through potentially long list of results, and can be &lt;a href="http://docs.tweepy.org/en/latest/code_snippet.html#handling-the-rate-limit-using-cursors"&gt;rate limited&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Best go ahead and make sure you have tweepy 3.9.0, because the previous version has a bug that means the cursors aren't handled correctly in this call;&lt;br /&gt;&lt;code&gt;pip3 install tweepy --upgrade&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Putting it all together you get something like;&lt;br /&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://chebe.dreamwidth.org/125117.html#cutid1"&gt;code&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;As I was manually deleting the DMs older than 30 days I noticed that twitter itself is using version 2 of their API, and doing a circuitous lookup via DM conversations. Something to look into when the new API is supported.&lt;br /&gt;&lt;br /&gt;But really, all this could have been avoided if twitter only provided a 'Delete Conversation' button in DMs.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=chebe&amp;ditemid=125117" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-04-20:105601:124559</id>
    <link rel="alternate" type="text/html" href="https://chebe.dreamwidth.org/124559.html"/>
    <link rel="self" type="text/xml" href="https://chebe.dreamwidth.org/data/atom/?itemid=124559"/>
    <title>Resizing images in python with pillow</title>
    <published>2020-12-02T20:04:25Z</published>
    <updated>2020-12-02T20:04:25Z</updated>
    <category term="python"/>
    <category term="code"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">Hello Internet. It's been a while, huh? Like many people, I got caught up in completely reconfiguring my workspace to accommodate a work-from-home station. Just yesterday I got to close all my IKEA tabs. It felt good. But unfortunately I haven't had the opportunity to get much work done on projects.&lt;br /&gt;&lt;br /&gt;One of the short things I did manage was an update to my &lt;a href="https://chebe.dreamwidth.org/121807.html"&gt;tweet-my-blog script&lt;/a&gt;, because my photos got too big so I needed to add handling to downsize before posting.&lt;br /&gt;&lt;br /&gt;First, pull in a new library;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;pip3 install pillow&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then update the script (changes in &lt;strong&gt;strong&lt;/strong&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://chebe.dreamwidth.org/124559.html#cutid1"&gt;code&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=chebe&amp;ditemid=124559" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-04-20:105601:121807</id>
    <link rel="alternate" type="text/html" href="https://chebe.dreamwidth.org/121807.html"/>
    <link rel="self" type="text/xml" href="https://chebe.dreamwidth.org/data/atom/?itemid=121807"/>
    <title>Pi Life, part two</title>
    <published>2020-07-11T12:35:34Z</published>
    <updated>2020-07-11T12:48:26Z</updated>
    <category term="python"/>
    <category term="raspberrypi"/>
    <category term="letsencrypt"/>
    <dw:security>public</dw:security>
    <dw:reply-count>1</dw:reply-count>
    <content type="html">In &lt;a href="https://chebe.dreamwidth.org/121435.html"&gt;Pi Life, part one&lt;/a&gt; I only got as far as making my raspberry pi functional again through upgrade. Now on to the script I want to put on it.&lt;br /&gt;&lt;br /&gt;After doing a project, and writing it up, I am usually too lazy to tweet my own blog posts, so I wrote a little python script to scrape &lt;a href="https://chebe.dreamwidth.org/data/rss"&gt;my RSS feed&lt;/a&gt; and post a link to the most recent post to twitter. (For people who don't use RSS.)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Step Two; create twitter app entry and get access tokens&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;This part seems to change constantly, so here are some posts I used to help me along the way;&lt;br /&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/how-to-create-a-twitter-app"&gt;https://www.digitalocean.com/community/tutorials/how-to-create-a-twitter-app&lt;/a&gt;&lt;br /&gt;&lt;a href="https://iag.me/socialmedia/how-to-create-a-twitter-app-in-8-easy-steps/"&gt;https://iag.me/socialmedia/how-to-create-a-twitter-app-in-8-easy-steps/&lt;/a&gt;&lt;br /&gt;&lt;a href="https://code.tutsplus.com/articles/creating-a-twitter-oauth-application--net-16614"&gt;https://code.tutsplus.com/articles/creating-a-twitter-oauth-application--net-16614&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Step Three; create python script&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Assuming you have python3 already;&lt;br /&gt;&lt;code&gt;pip3 install tweepy&lt;br /&gt;pip3 install feedparser&lt;br /&gt;pip3 install bs4&lt;br /&gt;pip3 install lxml&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;And because &lt;code&gt;BeautifulSoup&lt;/code&gt; can't seem to find &lt;code&gt;lxml&lt;/code&gt; this way;&lt;br /&gt;&lt;code&gt;sudo apt-get install python3-lxml&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Create a python script something like this (the exact code will depend on the structure of your RSS);&lt;br /&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://chebe.dreamwidth.org/121807.html#cutid1"&gt;code&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Step Four; deal with errors&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;My main error happened when I wanted to get an image used in a post. My images are self-hosted, &lt;a href="https://letsencrypt.org/"&gt;Let's Encrypt&lt;/a&gt; &lt;a href="https://chebe.dreamwidth.org/104694.html"&gt;signed&lt;/a&gt;. And the python3 libraries were not happy;&lt;br /&gt;&lt;code&gt;ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Now you can just turn off verification;&lt;br /&gt;&lt;code&gt;response = get(img_link, verify=False)&lt;/code&gt;&lt;br /&gt;But you still get an annoying warning message.&lt;br /&gt;&lt;br /&gt;I tried &lt;strong&gt;so many&lt;/strong&gt; different ways to try and fix this. This is the only thing I found that worked.&lt;br /&gt;&lt;br /&gt;First, go to &lt;a href="https://letsencrypt.org/certificates/"&gt;Let's Encrypt Certs&lt;/a&gt; and save the &lt;a href="https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt"&gt;Intermediate, Active, cross-signed cert&lt;/a&gt;. Remove the &lt;code&gt;.txt&lt;/code&gt; suffix. Verify this cert fixes the error for you with;&lt;br /&gt;&lt;code&gt;curl &lt;a href="https://your_website"&gt;https://your_website&lt;/a&gt; --cacert /path/to/lets-encrypt-x3-cross-signed.pem&lt;/code&gt;&lt;br /&gt;If no errors, all good.&lt;br /&gt;&lt;br /&gt;Now, in python;&lt;br /&gt;&lt;code&gt;import certifi&lt;br /&gt;print(certifi.where())&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Mine returns &lt;code&gt;/home/pi/.local/lib/python3.7/site-packages/certifi/cacert.pem&lt;/code&gt;&lt;br /&gt;Edit this file, append everything in &lt;code&gt;lets-encrypt-x3-cross-signed.pem&lt;/code&gt; to the end. (Leave a comment telling yourself what you did for future.) Save and exit. Rerun the tweeting python script.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Step Five;&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Glory in the lack of errors/warnings. And automatically created tweets, I guess.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=chebe&amp;ditemid=121807" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-04-20:105601:96574</id>
    <link rel="alternate" type="text/html" href="https://chebe.dreamwidth.org/96574.html"/>
    <link rel="self" type="text/xml" href="https://chebe.dreamwidth.org/data/atom/?itemid=96574"/>
    <title>Pimoroni Pirate Radio tweak; aka 'Talk to me Sweetie!'</title>
    <published>2017-03-27T23:21:44Z</published>
    <updated>2021-11-21T20:02:10Z</updated>
    <category term="raspberrypi"/>
    <category term="python"/>
    <dw:mood>chipper</dw:mood>
    <dw:security>public</dw:security>
    <dw:reply-count>1</dw:reply-count>
    <content type="html">You know what's super annoying? Not knowing the ip-address of the server you're trying to access. I &lt;em&gt;could&lt;/em&gt; scan the network and find the right machine. But, I'm lazy. And, the server knows its own ip, it should simply tell me.&lt;br /&gt;&lt;br /&gt;This is something I believed my &lt;a href="https://chebe.dreamwidth.org/96368.html"&gt;Pirate Radio&lt;/a&gt; could manage. When the &lt;a href="https://shop.pimoroni.com/products/phat-beat"&gt;pHAT BEAT&lt;/a&gt; bonnet gets installed it sets itself up with a daemon in /usr/bin. Technically I installed it twice (once for spotipy as well). I don't know if the code differs, but as I installed vlc-radio last, that's the code I will play with.&lt;br /&gt;&lt;br /&gt;Think it through. I've just booted up the server. The volume and power buttons do very necessary jobs, so we'll leave them alone. The fast-forward and rewind buttons start playing a station/cycle through stations. Very useful if you can't be bothered finding the ip-address. That leaves Play/Pause, which doesn't do anything until a station has started streaming. And if I have access to the web interface, well I can do that very job there. That's it, I'm sacrificing Play/Pause!&lt;br /&gt;&lt;br /&gt;In the end I simply replaced &lt;a href="https://github.com/pimoroni/phat-beat/blob/master/projects/vlc-radio/phatbeatd/usr/bin/phatbeatd"&gt;line#204&lt;/a&gt; with a call out to my script;&lt;br /&gt;&lt;code&gt;myip.read_ip()&lt;/code&gt;&lt;br /&gt;(making sure to import it at the top of the file. Let's hear it for the wonders of Open Source!)&lt;br /&gt;&lt;br /&gt;What script you ask? A simple one, to parse the wlan0 ip from ifconfig, and then a call to text-to-speech to actually read it out loud to me.&lt;br /&gt;&lt;br /&gt;You'll probably need to install the text-to-speech stuff;&lt;br /&gt;&lt;code&gt;sudo pip3 install pyttsx3&lt;br /&gt;sudo apt-get install espeak&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then save this as a file named myip.py (or whatever) into /usr/bin&lt;br /&gt;&lt;code&gt;&lt;pre&gt;
#!/usr/bin/env python3

import os, pyttsx3, time

def read_ip():
    &lt;strike&gt;f = os.popen('ifconfig wlan0 | grep "inet\ addr" | cut -d: -f2 | cut -d" " -f1')&lt;/strike&gt;
    f = os.popen("ifconfig wlan0 | grep 'inet ' | awk '/inet/ {print $2}'")
    your_ip = f.read()

    if not your_ip:
        your_ip = "not online"
    
    engine = pyttsx3.init()
    engine.say(your_ip)
    engine.runAndWait()

    time.sleep(3)
    print your_ip

if __name__ == '__main__':
    read_ip()
&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;And sure, give it a reboot to make sure the changes are picked up.&lt;br /&gt;&lt;br /&gt;Now, when I press play the Pirate Radio reads out its ip-address to me! So handy.&lt;br /&gt;(Note; if you press play with monitor and OTG cable attached, it'll probably crash and reboot. So don't do that.)&lt;br /&gt;&lt;br /&gt;*edit* 2020-07-10&lt;br /&gt;*edit* 2021-08-12 python3 version&lt;br /&gt;*edit* 2021-11-21 proper python3 version&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=chebe&amp;ditemid=96574" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-04-20:105601:94026</id>
    <link rel="alternate" type="text/html" href="https://chebe.dreamwidth.org/94026.html"/>
    <link rel="self" type="text/xml" href="https://chebe.dreamwidth.org/data/atom/?itemid=94026"/>
    <title>Quantified Self and Fitbit sleep data</title>
    <published>2016-12-11T21:30:16Z</published>
    <updated>2016-12-12T11:25:49Z</updated>
    <category term="python"/>
    <category term="fitbit"/>
    <category term="quantified self"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">This weekend involved getting to see Placebo in concert, so not much else happened. But that's the great thing about software, you can be productive without getting out of bed.&lt;br /&gt;&lt;br /&gt;I recently attended a &lt;a href="https://www.meetup.com/Quantified-Self-Dublin/"&gt;Quantified Self&lt;/a&gt; meetup on sleep, that gave me the kick up the arse I've been needing. (Which was only compounded when I heard about Pebble closing, and that Fitbit would take over their servers, and staff.) One of the presenters talked about how he got his Fitbit data and how he analysed it. (If you're interested, &lt;a href="http://www.slideshare.net/AlexMartinelli3/a-quest-for-better-sleep"&gt;slides are here&lt;/a&gt;, and &lt;a href="https://medium.com/@5agado/a-quest-for-better-sleep-with-fitbit-data-analysis-5f10b3f548a#.qovwfe2jg"&gt;blog post here&lt;/a&gt;.) He switched to using the official APIs when they became available, but I went with his original approach, &lt;a href="https://github.com/andrewjw/python-fitbit"&gt;a python program to log in and get your intraday data points&lt;/a&gt; instead of the aggregated stuff you get on the dashboard.&lt;br /&gt;&lt;br /&gt;I haven't been the most steady wearable user, but there were a few months when I wore it reliably. Simply because I was sleeping terribly and wanted to understand just how badly. Although I never got around to actually analaysing the data, until now. (That's one thing about all these QS talks, typically everyone showing their data is the picture of good health. I'm more interested in seeing what it looks like when it goes wrong.)&lt;br /&gt;&lt;br /&gt;I used the website dashboard to find the months that actually contained data. Then I exported csv files, month-by-month, using the official export option. This is the aggregated information, but it will be nice to see if it correlates with the intraday info.&lt;br /&gt;&lt;br /&gt;Then armed with dates that contain valid data, I put them into the python program, and grabbed all my data. In short, download and extract the source code. In the same folder as setup.py create your own python file, where you will create your own client. (This information is apparently in the example files, but I poked around before I noticed that.) To create your own client you just pass in your email address and password;&lt;br /&gt;&lt;code&gt;client = fitbit.Client.login(email="bob@example.com", password="password")&lt;/code&gt;&lt;br /&gt;You grab the specific info you're interested in;&lt;br /&gt;&lt;code&gt;client.intraday_sleep(date)&lt;/code&gt;&lt;br /&gt;And then dump it to screen/file/whatever you want. Although it's a good idea to format it a little.&lt;br /&gt;&lt;br /&gt;Sleep data is recorded as one value per minute. &lt;br /&gt;&lt;code&gt;&lt;br /&gt;# The different values for sleep are:&lt;br /&gt;#   0: no sleep data&lt;br /&gt;#   1: asleep&lt;br /&gt;#   2: awake&lt;br /&gt;#   3: very awake&lt;br /&gt;&lt;br /&gt;# data will be a similar list of tuples, but spaced one minute apart&lt;br /&gt;# [&lt;br /&gt;#   (datetime.datetime(2010, 2, 20, 23, 59), 2),&lt;br /&gt;#   (datetime.datetime(2010, 2, 21, 0, 0), 1),&lt;br /&gt;#   (datetime.datetime(2010, 2, 21, 0, 1), 1),&lt;br /&gt;#   ....&lt;br /&gt;#   (datetime.datetime(2010, 2, 21, 8, 34), 1),&lt;br /&gt;# ]&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;And then, we are left with the task of analysing the data. Which is a much bigger one.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=chebe&amp;ditemid=94026" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
</feed>
