Fixing the Magic Mirror Calendar

November 24th, 2014 3 min read

Github

The source code or files in this post are available on GitHub.

Series

This post is part of the MagicMirror series. Check out the other posts here:

    Tags

    Ads via Carbon

    This week I received some reports that the Magic Mirror calendar section stopped working. Since the mirror gracefully hides the calendar data, I didn’t really notice it on my own Magic Mirror. Of course, this must be fixed. 

    To figure out what was wrong, I started with the feed url. When I entered this in my browser, the .ical file was correctly downloaded, and after opening, it seems to look fine …

    image

    The next step in the calendar display process is the proxy script: calendar.php, since an Ajax request direct to the iCloud servers is not permitted. After opening this calendar.php file in my browser, the issue was visible: it only shows some useless coded garbish.

    image

    Somehow, the feed could not be correctly downloaded by the calendar.php. Till now, this was done, using the following line: 

    echo file_get_contents($url);
    

    Since, the file_get_contents isn’t very sophisticated, I tried switching to curl:

    <?php
    
    // Set the url of the calendar feed.
    $url = 'https://p01-calendarws.icloud.com/ca/subscribe/1/...';
    
    // Initialize the curl request.
    $ch = curl_init();
    
    // Set the CURL url.
    curl_setopt ($ch, CURLOPT_URL, $url);
    
    // Make sure redirects are followed.
    curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, true);
    
    // Execute the request and echo the response.
    echo curl_exec($ch);
    
    // Close the CURL request.
    curl_close($ch);
    

    Unfortunately, this still gave the same result. So time to dive in the CURL documentation. CURL has a lots of options that can be set by above used curl_setopt() function. So chances are, a solution is hidden within these options.

    After some reading, I found the CURLOPT_ENCODING option:

    The contents of the “Accept-Encoding: ” header. This enables decoding of the response. Supported encodings are “identity”, “deflate”, and “gzip”. If an empty string, “”, is set, a header containing all supported encoding types is sent.

    After setting this flag to true, the script outputted the desired format. Setting the flag before the echo was simple: 

    curl_setopt ($ch, CURLOPT_ENCODING, true);
    

    It seems Apple recently turned on gzip compression on their iCal webservers.

    Unfortunately, after testing it on my actual Raspberry Pi, I found out that my PHP installation on my RPi does not support CURL. But since I now found the reason and solution, some googling brought me to a post on BinaryTides which shows a file_get_contents()way to use decoding. Using this solution, I now got my calendar up and running again, using the following code:

    <?php
    
    // Set the url of the calendar feed.
    $url = 'https://p01-calendarws.icloud.com/ca/subscribe/...';
    
    /*****************************************/
    
    // Run the helper function with the desired URL and echo the contents.
    echo get_url($url);
    
    // Define the helper function that retrieved the data and decodes the content.
    function get_url($url)
    {
        //user agent is very necessary, otherwise some websites like google.com wont give zipped content
        $opts = array(
            'http'=>array(
                'method'=>"GET",
                'header'=>"Accept-Language: en-US,en;q=0.8rn" .
                            "Accept-Encoding: gzip,deflate,sdchrn" .
                            "Accept-Charset:UTF-8,*;q=0.5rn" .
                            "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:19.0) Gecko/20100101 Firefox/19.0 FirePHP/0.4rn"
            )
        );
    
        $context = stream_context_create($opts);
        $content = file_get_contents($url ,false,$context);
    
        //If http response header mentions that content is gzipped, then uncompress it
        foreach($http_response_header as $c => $h)
        {
            if(stristr($h, 'content-encoding') and stristr($h, 'gzip'))
            {
                //Now lets uncompress the compressed data
                $content = gzinflate( substr($content,10,-8) );
            }
        }
    
        return $content;
    }
    

    Of course, this fix is included in the Magic Mirror Repository on GitHub.

    Man, it feels good if you solve a bug! :)

    image
    Loading comments …
    ©2021 - MichaelTeeuw.nl