顯示具有 AR 標籤的文章。 顯示所有文章
顯示具有 AR 標籤的文章。 顯示所有文章

2026年3月30日 星期一

[水井USR] 在Pythonanaywhere上用Django實作標籤AR來播放影片

 


成果網站:https://interactivear.pythonanywhere.com/

標籤:


1.mysite/templates/marker_list.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
  <meta charset="utf-8">
  <title>AR 標籤列表</title>
</head>
<body>
  <h1>AR 標籤列表</h1>

  {% for marker in markers %}
    <div style="margin-bottom:24px;border:1px solid #ccc;padding:16px;">
      <h3>{{ marker.title }}</h3>
      {% if marker.preview_image %}
        <img src="{{ marker.preview_image.url }}" style="max-width:240px;">
      {% endif %}
      <p>{{ marker.description }}</p>
      <a href="{% url 'ar_player' marker.slug %}">開啟 AR 頁面</a>
    </div>
  {% empty %}
    <p>目前沒有可用的 AR 標籤。</p>
  {% endfor %}
</body>

</html>

2.mysite/templates/index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
  <meta charset="utf-8">
  <title>{{ marker.title }}</title>
  <script src="https://aframe.io/releases/1.6.0/aframe.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/mind-ar@1.2.5/dist/mindar-image-aframe.prod.js"></script>
  <style>
    html, body {
      margin: 0;
      overflow: hidden;
      width: 100%;
      height: 100%;
    }
  </style>
</head>
<body>
  <a-scene
    mindar-image="imageTargetSrc: {{ marker.target_file.url }}; autoStart: true;"
    embedded
    color-space="sRGB"
    renderer="colorManagement: true, physicallyCorrectLights"
    vr-mode-ui="enabled: false"
    device-orientation-permission-ui="enabled: false"
  >
    <a-assets>
      <video
        id="video"
        src="{{ marker.video_file.url }}"
        preload="metadata"
        loop
        playsinline
        webkit-playsinline
        crossorigin="anonymous"
      ></video>
    </a-assets>

    <a-camera position="0 0 0" look-controls="enabled: false"></a-camera>

    <a-entity id="target" mindar-image-target="targetIndex: 0">
      <a-video
        id="video-plane"
        src="#video"
        position="0 0 0"
      ></a-video>
    </a-entity>
  </a-scene>

  <script>
    const target = document.querySelector("#target");
    const video = document.querySelector("#video");
    const videoPlane = document.querySelector("#video-plane");

    // 依標籤比例設定尺寸,而不是依影片比例
    const targetWidth = {{ marker.target_width }};
    const targetHeight = {{ marker.target_height }};

    const width = 1;
    const height = targetHeight / targetWidth;

    videoPlane.setAttribute("width", width);
    videoPlane.setAttribute("height", height);

    target.addEventListener("targetFound", async () => {
      try {
        video.currentTime = 0;
        await video.play();
      } catch (err) {
        console.log("播放失敗", err);
      }
    });

    target.addEventListener("targetLost", () => {
      video.pause();
    });

    document.body.addEventListener("click", async () => {
      try {
        await video.play();
        video.pause();
      } catch (err) {
        console.log("初始化影片失敗", err);
      }
    }, { once: true });
  </script>
</body>
</html>

3.mysite/myapp/views.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# myapp/views.py
from django.shortcuts import render, get_object_or_404
from .models import ARMarker


def ar_marker_list(request):
    markers = ARMarker.objects.filter(is_active=True).order_by("-created_at")
    return render(request, "marker_list.html", {"markers": markers})


def ar_player(request, slug):
    marker = get_object_or_404(ARMarker, slug=slug, is_active=True)
    return render(request, "index.html", {"marker": marker})

4.mysite/myapp/models.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# myapp/models.py
from django.db import models


class ARMarker(models.Model):
    title = models.CharField("標題", max_length=100)
    slug = models.SlugField("代稱", unique=True)

    preview_image = models.ImageField(
        "辨識圖片預覽",
        upload_to="ar/preview/",
        help_text="這張是給管理者看的預覽圖,不是直接給 MindAR 辨識用。"
    )

    target_file = models.FileField(
        "MindAR target 檔",
        upload_to="ar/targets/",
        help_text="請上傳 .mind 檔案"
    )

    video_file = models.FileField(
        "AR 影片",
        upload_to="ar/videos/"
    )

    target_width = models.PositiveIntegerField(
        "標籤寬度基準",
        default=1,
        help_text="請填入辨識圖的原始寬度,例如 1080"
    )

    target_height = models.PositiveIntegerField(
        "標籤高度基準",
        default=1,
        help_text="請填入辨識圖的原始高度,例如 1920"
    )

    description = models.TextField("說明", blank=True)
    is_active = models.BooleanField("啟用", default=True)
    created_at = models.DateTimeField("建立時間", auto_now_add=True)
    updated_at = models.DateTimeField("更新時間", auto_now=True)

    class Meta:
        verbose_name = "AR標籤"
        verbose_name_plural = "AR標籤"

    def __str__(self):
        return self.title

5.mysite/myapp/admin.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
from django.contrib import admin
from django.utils.html import format_html
from .models import ARMarker


@admin.register(ARMarker)
class ARMarkerAdmin(admin.ModelAdmin):
    list_display = (
        "id",
        "title",
        "slug",
        "is_active",
        "target_ratio",
        "preview_thumb",
        "created_at",
    )
    list_filter = ("is_active", "created_at")
    search_fields = ("title", "slug", "description")
    prepopulated_fields = {"slug": ("title",)}
    readonly_fields = (
        "preview_thumb_large",
        "created_at",
        "updated_at",
    )
    ordering = ("-created_at",)
    list_per_page = 20

    fieldsets = (
        ("基本資料", {
            "fields": ("title", "slug", "description", "is_active")
        }),
        ("AR 檔案", {
            "fields": (
                "preview_image",
                "preview_thumb_large",
                "target_file",
                "video_file",
            )
        }),
        ("標籤尺寸設定", {
            "description": "請填入辨識圖的原始寬高,用來讓 AR 影片比例與標籤一致。",
            "fields": ("target_width", "target_height"),
        }),
        ("系統資訊", {
            "fields": ("created_at", "updated_at")
        }),
    )

    def preview_thumb(self, obj):
        if obj.preview_image:
            return format_html(
                '<img src="{}" style="height:50px;width:auto;border-radius:4px;object-fit:contain;" />',
                obj.preview_image.url
            )
        return "-"
    preview_thumb.short_description = "預覽"

    def preview_thumb_large(self, obj):
        if obj and obj.preview_image:
            return format_html(
                '<img src="{}" style="max-height:240px;max-width:100%;border-radius:8px;object-fit:contain;" />',
                obj.preview_image.url
            )
        return "尚未上傳圖片"
    preview_thumb_large.short_description = "圖片預覽"

    def target_ratio(self, obj):
        if obj.target_width and obj.target_height:
            return f"{obj.target_width} × {obj.target_height}"
        return "-"
    target_ratio.short_description = "標籤尺寸"

6.mysite/mysite/urls.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
"""
URL configuration for mysite project.

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/5.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""

from django.contrib import admin
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from myapp.views import ar_player, ar_marker_list

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", ar_marker_list, name="ar_marker_list"),
    path("<slug:slug>/", ar_player, name="ar_player"),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

7.mysite/mysite/settings.py

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
"""
Django settings for mysite project.

Generated by 'django-admin startproject' using Django 5.1.3.

For more information on this file, see
https://docs.djangoproject.com/en/5.1/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.1/ref/settings/
"""

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-me+v(tu349%8@$hwf=^6z0de%u!0%yha1fi6z7&31(_1-lgl72"

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ['InteractiveAR.pythonanywhere.com']


# Application definition

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "myapp",
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
]

ROOT_URLCONF = "mysite.urls"

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [BASE_DIR / 'templates'],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    },
]

WSGI_APPLICATION = "mysite.wsgi.application"


# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
    }
}


# Password validation
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
    },
]


# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/

LANGUAGE_CODE = "en-us"

TIME_ZONE = "UTC"

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/

STATIC_URL = "static/"

# Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

# default static files settings for PythonAnywhere.
# see https://help.pythonanywhere.com/pages/DjangoStaticFiles for more info
MEDIA_ROOT = '/home/InteractiveAR/mysite/media'
MEDIA_URL = '/media/'
STATIC_ROOT = '/home/InteractiveAR/mysite/static'
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    BASE_DIR / "static",
]
STATIC_ROOT = BASE_DIR / 'staticfiles'


2022年1月30日 星期日

MindAR:人臉擴增實境應用

 MindAR教學文件:https://hiukim.github.io/mind-ar-js-doc/face-tracking-quick-start/webpage

AFrame教學文件:https://aframe.io/

編輯工具:Notepad++

測試工具:Web Server for Chrome

1.利用Notepad++編輯程式,範例一:Minimal Example,原始程式如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.0.0/dist/mindar-face.prod.js"></script>
    <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.0.0/dist/mindar-face-aframe.prod.js"></script>
  </head>

  <body>
    <a-scene mindar-face embedded color-space="sRGB" renderer="colorManagement: true, physicallyCorrectLights" vr-mode-ui="enabled: false" device-orientation-permission-ui="enabled: false">
      <a-camera active="false" position="0 0 0"></a-camera>

      <a-entity mindar-face-target="anchorIndex: 1">
    <a-sphere color="green" radius="0.1"></a-sphere>
      </a-entity>
    </a-scene>
  </body>
</html>

在程式的第4-6行中,分別告知MindAR臉部辨識、AFrame、以及MindAR臉部辨識與AFrame的腳本的來源。第10行中<a-scene>屬性mindar-face說明是由 MindAR 引擎來控制這個場景,第13行<a-entity> 屬性 mindar-face-target="anchorIndex: 1",說明引擎將跟踪特定的錨點位置-鼻尖。記得存成html文件,本範例為test2.html,並建立TreeArt資料夾。

2.開啟Web Server for Chrome,按下"啟用應用程式"。


3.按下上圖中"CHOOSE FOLDER",選擇儲存test2.html程式的資料夾TreeArt。

4.開啟Chrome瀏覽器,輸入http://127.0.0.1:8887/test2.html網址,就可看到一顆球在鼻尖上



5.修改anchorIndex: 1變成anchorIndex: 200,球就跑到下巴。

6. 參加AFrame文件或"好玩的WebVR,A-Fame一個針對3D/AR/VR所設計的網路框架"
,將a-sphere替換成a-box。


以下是有關臉部特點的測試:
臉部的特徵圖如下:

臉部特徵點測試:

雙人測試:


2020年10月5日 星期一

魔法豬樂園:Open API教學文章

利用Python、網站設計、擴增實境、開放資料介面和直播電商活絡南投縣民間鄉的場域-豬樂園科技導入場域單位:智創生活科技有限公司南開科技大學創業歸故里

智創聯盟是教育部智活二期六個跨校型教學聯盟中心之一,中心學校是南開科技大學,夥伴學校有:國立台中教育大學、國立高雄科技大學、國立虎尾科技大學、國立台東專科學校、亞洲大學、逢甲大學、高苑科技大學。計畫從2015/5/1到2019/1/31止,為了讓聯盟成果能持續擴散,於2020年參加創業歸故里競賽,實踐場域選擇在南投縣名間鄉豬樂園。

Python是現今使用在人工智慧以及資料處理的火紅程式語言,我們使用Python來讀取政府提供的開放資料,利用簡單程式就能輕鬆地運用開放資料,本教材以南投縣名間鄉豬樂園相關的觀光旅遊為主。


開放資料來源:
  1. 當Python遇見猪樂園,來看南投縣毛猪成交頭數-總數
  2. 用Python找出猪樂園附近的農村地方美食小吃特色料理
  3. 取得南投縣名間鄉的美食資訊
  4. 取得南投縣名間鄉的景點資料
  5. 南投以豬肉聞名的小吃店
  6. 找出南投有"豬"元素的景點
  7. 體驗農村生活-農村主題旅遊規劃
  8. 食物資訊樣貌API使用
  9. 找出所有豬食物資訊樣貌

2019年10月13日 星期日

使用Unity和Vuforia以擴增實境方式來製作生日快樂影片播放APP

請先參考前一篇文章,"利用Unity和Vufroia來設計擴增實境"。

1. 更換成生日快樂的Target。


2.增加一個Plane的物件,記得滙入影片。

3.將Mesh Renderer取消,讓Plane物件呈現透明。

4.調整大小,使其和卡片一樣大。

5.增加元件,選擇Add Component。

6. 增加Video Player元件。

7.選擇影片。

8.設定播放影片

9.編譯成APK

10.測試

11. 影片反轉,可以把Plane物件的y值設為180。


利用Unity和Vufroia來設計擴增實境

1.打開Unity建立新檔


2.刪除Main Camera物件

3. 打開File->Build Settings

4.切換Andriod平台

5.按下Player Settings,在XR Settings中,設定Vuforia Augment Realty。

6.取消multithreaded Rendering以及設定Pachage Name,要全部都小寫,而且至少要兩層,換句話說要有一個"."

7. 增加vuforia/CameraAR物件

8. 增加Vuforia/Image物件

9.打開Asset Store,並把視寫設定為Maximize。

10. 下載Unity-Chan模型並滙入(Import)。

11. 打開Vuforia,在Target Manager中把圖片上傳,並選擇想要的Target,再按下Download Database,記得選Unity格式輸出。

12. 再Unity下,在Asset視窗下按下右鍵,選擇Import Package->Custom Package,滙入第11步驟的資料庫檔案。

13. 選擇Image Target,在右邊選擇剛滙入的資料庫以及選擇圖片。

14.選擇CamaraAR物件,打開 Open Vuforia configuration

15. 在Vuforia License Manager中產生一個Development Key,選擇該KEY,複製全部KEY。

16.打上一個步驟中的Key貼在Open License Key中。

17.打開Unity-chan!中的Prefabs,選擇最右邊的unitychan_dynamic,拖移至左上角的Image Target上。

18. 最後編譯製作成APK檔

19.執行結果



2019年9月22日 星期日

畫點做AR

一個免費的擴增實境軟體,稱為DotAR。
網址:https://assetstore.unity.com/packages/tools/dot-ar-97973

1.按下Import鈕,直接滙入。

2.選擇Project->Assests->Smaple->DotAR_Sample.unity

3.選擇File->Build Settings->Android->Switch Platform

4.選擇Player Settings,把Package name改成com.dot.ar
5.按下Build鏈,將生成的APK檔放到手機上,進行安裝。

6.進行測試

以下是官方的影片

2018年1月1日 星期一

Vuforia 7讓擴增實境更貼進我們的生活

在2017年12月19日Vuforia推出新版本 - Vuforia 7,發表"Vuforia 7 is Available!"的文章,這個版本有三個主要的特點,分述如下:

  1. Vuforia模型目標(Vuforia Model Targets)”透過形狀來識別物體,而現有的方法是以平面影像上的特徵點,例如:平面印刷品、產品包裝和許多消費品上。 模型目標是完美的,可以把數位內容聯結到工業設備、汽車或家用電器等物品上。
  2. Vuforia地平面 (Vuforia Ground Plane)”可以將數位內容呈現在地面、天花板或桌面上,Vuforia構建一個可視化應用的理想解決方案,從家俱購買到擴增實境的設計評論。 地平面功能支持從啟用的iOS設備的ARKit開始到各式各樣的設備 ,擴展到時下流行的Android和iOS設備。
  3. Vuforia聚變 (Vuforia Fusion)”是全新的功能,主要是用來解決在相機、傳感器、晶片組、以及軟體框架(ARKit和ARCore)等內部支持AR技術的碎片化(Fragmentation)問題。 借助Vuforia聚變應用程應可自動提供解決此問題,而不需要額外的工作。
Vuforia模型目標(Vuforia Model Targets)


Vuforia地平面 (Vuforia Ground Plane)



Vuforia聚變 (Vuforia Fusion)用在同步定位與地圖構建(SLAM或Simultaneous localization and mapping)視覺慣性測程(visual inertial odometry)

2017年12月16日 星期六

Web AR工具:AR.js - Efficient Augmented Reality for the Web

一套以網頁為主的擴增實境的工具AR.js,一套簡好用的工具,可以適合平台用瀏覽器來開啟AR的功能。

範例網站:https://webxr.io/webar-playground/



測試步驟:
1. 列印標籤,網址:http://augmentmy.world/wp-content/uploads/2016/09/Hiro-pattern.pdf
2. 打開網站,網址:https://webxr.io/webar-playground/
3.按下Start鍵,拿起標籤,測試結果如下:


2017年12月9日 星期六

在PC安裝BlueStacks手機模擬器測式擴增實境APPs

本文將介紹一個好用的工具,在PC上裝BlueStacks手機模擬器,就可以使用Android APPs,目前支援Windows和Mac版本。官方網站:https://www.bluestacks.com/tw/index.html


 

BlueStacks手機模擬器測試AR的文章Vuforia Standalone using Bluestacks – Starting Android App on PC,在該篇文章中介紹兩款APP: Animals of Africa Tales of the World




大家可以利用該篇文章提供的圖片進行測試,記得要先安裝APP。


(Animals of Africa)

(Tales of  the World)




2017年12月1日 星期五

擴增實境與物聯網結合的應用影片

物聯網可以提供物品對物品通訊的功能,感知器(如溫溼度、PM2.5等)可以將訊息經由控制器傳送到雲端伺服主機,控制器也能從雲端伺服主機中取得資料,經過運算後,就能啟閉致動器(馬達、警報器等)。

擴增實境技術能將電腦的資訊呈現在現實生活中,因此結合物聯網技術,就能把生活中的感測器的數值用擴增實境技術呈現在我們生活世界中,經由人們和擴增實境提供的人機介互動,有了物聯網的協助就能操控現實世界的設備,如家電產品等。







2017年11月30日 星期四

AR meets IoTs: 當擴增實境遇到物聯網-讀取感知訊息程式解析

AR meets IoTs: 當擴增實境遇到物聯網相關文章,如下:
初接觸
用網頁來控制LED亮滅
發佈感知訊息程式解析

在上圖我們可以清楚地看到在IoT content目錄下,有三個原始程式:
  1. IoT.cs
  2. ReadStream.cs
  3. WebStreamReader.cs

當您點選右上角的codeContainer,只看到兩個腳本程式,分別是IoT.cs和ReadStream.cs,但沒有看到WebStreamReader.cs。其實WebStreamReader是被宣告在ReadStream程式內,如下:


public class ReadStream : MonoBehaviour
{
public string PhotonParticleURL = "https://api.particle.io/v1/devices/events?access_token=649e7d09d0980e4b649e42f6dcff79887d9570e2";
WebStreamReader request = null;

我們以在ReadStream程式中找到WRequest()函式,您就可以看到程式是如何建立物件new WebStreamReader(),如何啟動網站連結Start(PhotonParticleURL),如何取得網站資料request.GetNextBlock(),再解析出溫度的資料Contains ("temperature"),最後再顯示在AR畫面上gameObject.GetComponent ().microTemperatureVal
IEnumerator WRequest()
{
request = new WebStreamReader();
request.Start(PhotonParticleURL); //https://www.ourtechart.com//wp-content/uploads/2016/04/jsonAllData.txt");
string stream = "";
while (true)
{
string block = request.GetNextBlock();
if (!string.IsNullOrEmpty(block))
{
stream += block;
//Debug.Log ("Stream1: " + stream);
string[] data = stream.Split(new string[] { "\n\n" }, System.StringSplitOptions.None);
//Debug.Log ("Data length: " + data.Length);
stream = data[data.Length - 1];

for (int i = 0; i < data.Length - 1; i++)
{
if (!string.IsNullOrEmpty(data[i]))
{
// Debug.Log ("Data: " + data [i]); // print all block of data (event + data)
if (data [i].Contains ("light")) {
lightTrue = true;
string output = data [i].Substring(data [i].IndexOf("{"));
parseDataLight = JsonUtility.FromJson (output);
//Debug.Log ("Data of Photoresistor: " + parseData.data);
//text.text = parseData.data.ToString ();
//gameObject.GetComponent ().microPhotoresistorVal = parseDataLight.data;
}
if (data [i].Contains ("temperature")) {
temperatureTrue = true;
string output = data [i].Substring(data [i].IndexOf("{"));
parseDataTemperature = JsonUtility.FromJson (output);
//Debug.Log ("Data of Temperature sensor: " + parseData.data);
//text.text = parseData.data.ToString ();
//gameObject.GetComponent ().microTemperatureVal = parseDataTemperature.data;
}
if (data [i].Contains ("motion")) {
motionTrue = true;
string output = data [i].Substring(data [i].IndexOf("{"));
parseDataMotion = JsonUtility.FromJson (output);
//Debug.Log ("Data of PIR sensor: " + parseData.data);
//text.text = parseData.data.ToString ();
//gameObject.GetComponent ().motionDetectedBool = Convert.ToBoolean(parseDataMotion.data);
}
if (data [i].Contains ("ultraviolet")) {
ultravioletTrue = true;
string output = data [i].Substring(data [i].IndexOf("{"));
parseDataUltraviolet = JsonUtility.FromJson (output);
//Debug.Log ("Data of PIR ultraviolet: " + parseData.data);
//text.text = parseData.data.ToString ();
//gameObject.GetComponent ().microUltravioletVal = parseDataUltraviolet.data;
}
if (data [i].Contains ("humidity")) {
humidityTrue = true;
string output = data [i].Substring(data [i].IndexOf("{"));
parseDataHumidity = JsonUtility.FromJson (output);
//Debug.Log ("Data of Humidity: " + parseData.data);
//text.text = parseData.data.ToString ();
//gameObject.GetComponent ().microHumidityVal = parseDataHumidity.data;
}
//Debug.Log ("TEst: " + humidityTrue + temperatureTrue + lightTrue + ultravioletTrue);
if (humidityTrue && temperatureTrue && lightTrue && ultravioletTrue) {
//Debug.Log ("PRINT ALLLLLLLLLLLLLL");
gameObject.GetComponent ().microPhotoresistorVal = parseDataLight.data;
gameObject.GetComponent ().microTemperatureVal = parseDataTemperature.data;
gameObject.GetComponent ().motionDetectedBool = Convert.ToBoolean(parseDataMotion.data);
gameObject.GetComponent ().microUltravioletVal = parseDataUltraviolet.data;
gameObject.GetComponent ().microHumidityVal = parseDataHumidity.data;
humidityTrue = false;
motionTrue = false;
temperatureTrue = false;
lightTrue = false;
ultravioletTrue = false;
}
}
}
}
yield return new WaitForSeconds(1);
}

真正要顯示在畫面上是IoT.cs的任務,在Update()中可以找溫度的片斷程式如下:

microTemperatureText.text = microTemperatureVal.ToString ();
checkTemperature ();

依照顏色來改變按鈕的顏色值:
private void checkTemperature() {
index = 0;
if (microTemperatureVal >= minTemp && microTemperatureVal <= maxTemp) // Green Color - temperature is ok
greenButtonColor (index);// (Buttons[0]);
if (microTemperatureVal > maxTemp) // Red Color - temperature is too Hot
orangeButtonColor(index);
if (microTemperatureVal < minTemp) // Blue Color - temperature is too Cold
blueButtonColor (index);
}