יום שבת, 6 בספטמבר 2014

Arduino Yun - CGI and Python




אחרי הכרות קצרה עם Arduino Yun הגיע השלב להעמיק פנימה, המאמר מתמקד על בניית ממשק Web מתקדם בניגוד למה שהדגמתי בעבר שהיה יחסית מוגבל הפעם נעזר ב CGI ובשפת Python על מנת להשלים את המשימה בצורה פשוטה והמהירה ביותר, אבל לפני שנתחיל כדאי להצטייד במספר כלים.
  • NotePad++ - כתיבת קוד והמרות קבצים בין Windows ל Linux.
  • WinScp - העברת קבצים בין ה Yun למחשב האישי.
  • Putty - התממשקות ב SSH ל Yun.

הגדרה ראשונית

שימו לב!
  • יש לגבות את קבצי המערכת לפני התחלת העבודה!
  • יש לגבות את ספריית www.
מערכת ההפעלה OpenWrt מגיעה עם שרת Web שנקרא uhttpd שדרכו ניגשים לממשק של ה Yun, נוכל להעזר בו בשביל האתר שלנו, כל מה שצריך לעשות הוא להוריד את קובץ ההגדרות (uhttpd) שנמצא בתיקייה /etc/config/ בעזרת WinSCP ולהוסיף שורה שמייצגת את ה interpreter של Python כפי שניתן לראות בדוגמה:

# List of extension->interpreter mappings.
# Files with an associated interpreter can
# be called outside of the CGI prefix and do
# not need to be executable.
# list interpreter ".php=/usr/bin/php-cgi"
# list interpreter ".cgi=/usr/bin/perl"
list interpreter   ".py=/usr/bin/python"


קוד

הדוגמה קצת יותר מורכבת מ Hello World פשוט ומכילה 2 דפים, הדף הראשון הוא ה Login שבעזרתו נקבל קלט מהמשתמש ונעביר אותו ב Get לדף השני, במקרה שעשינו טעות בשם המשתמש או הסיסמא השרת יזריק קוד של Javascript שיחזיר את הלקוח ל Login,

על מנת לא לפגוע באתר המקומי של ה Yun נוסיף תיקייה חדשה ב www/cgi-bin בה נאכסן את קבצי ה Python אבל לא נוכל להכניס בה את קבצי ה JS או ה CSS כי השרת יחשוב שהוא צריך להריץ אותם ויחפש את interpreter המתאים, לכן יש לאכסן את שאר הקבצים מחוץ לתייקית cgi-bin.

login.py

#!/usr/bin/env python
import os

#set http header, leave double space
print "Content-type: text/html"
print

#print html content
print """
     <html>
     <head>
     <title>Login</title>
     
     <meta name="viewport" 
     content="width=device-width,initial-scale=1,maximum-scale=1" />
     
     <link href="/../example/css/jquery.mobile-1.4.3.min.css" rel="stylesheet" type="text/css" />
     <script src="/../example/js/jquery-2.1.1.min.js" type="text/javascript"></script>
     <script src="/../example/js/jquery.mobile-1.4.3.min.js" type="text/javascript"></script>
     <script src="/../example/js/jquery.validate.min.js" type="text/javascript"></script>
     </head>
     
     <body>
          <form action="/cgi-bin/example/welcome.py" method="get">
             <div style="margin-top:5%;margin-left:5%;margin-right:5%">
                Name: <input type="text" name="txb_name">  <br />
             </div>
             <div style="margin-top:5%;margin-left:5%;margin-right:5%">
                Password: <input type="password" name="txb_password" />
             </div>

             <div style="margin-top:5%;margin-left:5%;margin-right:5%">
                <input type="submit" value="Submit" />
             </div>
          </form>

     </body>
     </html>
      """

welcome.py

#!/usr/bin/env python
import os
import cgi

form = cgi.FieldStorage()

# get date from post/get
name = form.getvalue('txb_name')
password  = form.getvalue('txb_password')

# set http header, leave double space
print "Content-type: text/html"
print

# write head
print """
    <html>
    <head>
    <title>Welcome</title>

    <meta name="viewport"
        content="width=device-width,initial-scale=1,maximum-scale=1" />
        
    <link href="/../example/css/jquery.mobile-1.4.3.min.css" rel="stylesheet" type="text/css" />
    <script src="/../example/js/jquery-2.1.1.min.js" type="text/javascript"></script>
    <script src="/../example/js/jquery.mobile-1.4.3.min.js" type="text/javascript"></script>
    </head>"""

# change body depend on the request
if password != "12345" and name != "proxytype":
   print """
        <body>
            <script type="text/javascript">
               window.location.href = 'login.py';
            </script>
            Redirecting...
        </body>
        </html>"""
else:
    print """
        </head>
        <body>
        <h1 style="margin-top:5%%;margin-left:5%%">Welcome, %s !</h1>
        </body>
        """ % (name)
# % is symbol for string formatting for return it in string enter double '%%'
# printing close tag
print "</html>"


נקודות נוספות

CGI רגיש מאוד ולפעמים עלולים לקבל שגיאות שלא תמיד ניתן להבין מה בדיוק הבעיה, רכזתי מספר טיפים שיפתרו את רוב התקלות:
  • Permissions - יש לוודא שהסקריפטים של ה Python נמצאים בתיקיית cgi-bin ושיש שלהם הרשאות גבוהות ניתן להעזר בפקודה ב chmod a+x, זה יעשה את העבודה.
  • (End Of Line (EOL - יש הבדל באיך מערכות ההפעלה מתייחסות לסוף השורה, ב Windows בכל סוף שורה יש את התווים r\n\ ולעומת זאת במערכות Unix רק את התו n\ לכן במקרה שכותבים ב Windows יש לשמור את הקבצים בהגדרת Unix בעזרת Notepad++:
זה הכרחי?!

  • (Bytes Order Mark (BOM - תו Unicode שמוכנס לתחילת הקובץ מאפשר להקל על צורת הקידוד במקרה של Unicode, UTF-16 ו UTF-32 במקרה שלנו נשתמש ב UTF-8 ככה שאין לו משמעות וצריכים להוריד אותו בעזרת Notepad++: 
קידוד עולם אכזר!



תוצאה סופית



סיכום

בעזרת Python בשילוב JavaScript ו Css נוכל לבנות ממשקי ניהול מורכבים, וזה בזכות ה Linux שמאפשר לנו לעבוד עם שירותים מתקדמים יותר ונפח זיכרון גדול לקבצים , אומנם הדגמתי על Python אבל אפשר לעבוד גם עם PHP רק שהוא לא מגיע באופן טבעי עם הלוח ויש להוריד אותו בנפרד.

ללא גבולות...