# Scale Temperature

## Lab 4: Scale Widget (Temperature Gauge)

***

### 1. โครงสร้างภาพรวมของ Lab

#### Why? - ทำไมต้องเรียนรู้เรื่องนี้

* **Professional Gauge**: Scale widget สร้างเครื่องมือวัดที่ดูเหมือนเครื่องมือจริง มี tick marks และ labels
* **Color Zones**: แสดง warning zones ด้วยสี (blue=cold, green=normal, red=hot) ซึ่งเป็นมาตรฐานในอุตสาหกรรม
* **Needle Display**: เข็มชี้ค่าปัจจุบันเหมือน analog gauge ดั้งเดิม
* **Multiple Modes**: ใช้ได้ทั้งแบบ vertical (thermometer) และ round (pressure gauge)
* **Industry Standard**: Scale/Gauge เป็นองค์ประกอบหลักของ SCADA, HMI, และ BMS (Building Management System)

#### What? - จะได้เรียนรู้อะไร

1. **Scale Widget**: สร้าง gauge ด้วย `lv_scale_create()`
2. **Tick Marks**: กำหนด total ticks, major tick interval, tick length
3. **Scale Sections**: เพิ่ม color zones (blue, green, red)
4. **Needle Line**: สร้างเข็มชี้ด้วย `lv_line_create()` บน scale
5. **Scale Modes**: HORIZONTAL, VERTICAL, ROUND\_INNER, ROUND\_OUTER

#### How? - จะทำอย่างไร

1. สร้าง Scale widget ในโหมด `LV_SCALE_MODE_ROUND_OUTER`
2. กำหนด tick count, major tick interval, label format
3. เพิ่ม 3 sections สำหรับ color zones
4. สร้าง needle line ชี้ค่าปัจจุบัน
5. ใช้ timer อัพเดทค่าจาก simulated sensor

<figure><img src="/files/4kvlWO80Jf3Y3w5PZuvr" alt=""><figcaption></figcaption></figure>

***

### 2. หลักการทำงานและ Flowchart

#### 2.1 Scale Anatomy

```
┌─────────────────────────────────────────────────────────────┐
│                    SCALE ANATOMY                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ROUND_OUTER Mode (Gauge):                                 │
│                                                             │
│              Labels (ตัวเลข)                                 │
│                 │                                           │
│                 ▼                                           │
│           0    10    20    30    40    50                   │
│          ╭─┬─┬─┬──┬─┬─┬──┬─┬─┬──┬─┬─╮                       │
│         ╱  │ │ │  │ │ │  │ │ │  │ │ │╲                      │
│        │   │ │ │  │ │ │  │ │ │  │ │ │ │                     │
│        │   │     │         │   │      │                     │
│        │  Minor  │  Major  │  Minor   │                     │
│        │  Ticks  │  Ticks  │  Ticks   │                     │
│        │         │         │          │                     │
│        │         │  NEEDLE │          │                     │
│        │         │    ╲    │          │                     │
│         ╲        │     ●──────────   ╱                      │
│          ╰───────┴──────────────────╯                       │
│                                                             │
│   Major Tick: ยาว, มี label ตัวเลข                            │
│   Minor Tick: สั้น, ไม่มี label                                 │
│   Needle: เข็มชี้ค่า (lv_line widget)                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

#### 2.2 Scale Modes

```
┌─────────────────────────────────────────────────────────────┐
│                   SCALE MODES                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   1. LV_SCALE_MODE_HORIZONTAL (แนวนอน)                      │
│      0───────10───────20───────30───────40                  │
│      |||  ||||  ||||  ||||  ||||                            │
│                                                             │
│   2. LV_SCALE_MODE_VERTICAL (แนวตั้ง - thermometer)           │
│      40 ─┤                                                  │
│         ─┤                                                  │
│      30 ─┤                                                  │
│         ─┤                                                  │
│      20 ─┤                                                  │
│         ─┤                                                  │
│      10 ─┤                                                  │
│         ─┤                                                  │
│       0 ─┤                                                  │
│                                                             │
│   3. LV_SCALE_MODE_ROUND_OUTER (gauge - ticks ด้านนอก)       │
│           ╭──┬──╮                                           │
│          ╱ 0  50 ╲                                          │
│         │ ┤    ├  │                                         │
│          ╲ ┤  ├  ╱                                          │
│           ╰──┴──╯                                           │
│                                                             │
│   4. LV_SCALE_MODE_ROUND_INNER (gauge - ticks ด้านใน)        │
│           ╭──────╮                                          │
│          ╱  ├  ├  ╲                                         │
│         │  0    50 │                                        │
│          ╲  ├  ├  ╱                                         │
│           ╰──────╯                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

#### 2.3 Color Sections (Temperature Zones)

```
┌─────────────────────────────────────────────────────────────┐
│                  COLOR SECTIONS                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   Temperature Gauge (-10 to 50 degC):                       │
│                                                             │
│   Section 1: COLD (Blue)     -10 to 10 degC                 │
│   Section 2: NORMAL (Green)   10 to 35 degC                 │
│   Section 3: HOT (Red)        35 to 50 degC                 │
│                                                             │
│           -10    10     35    50                            │
│           ╭──────┬──────┬──────╮                            │
│          ╱ BLUE  │GREEN │ RED   ╲                           │
│         │ ██████ │██████│██████ │                           │
│         │  COLD  │NORMAL│ HOT   │                           │
│          ╲ ██████│██████│█████ ╱                            │
│           ╰──────┴──────┴─────╯                             │
│                                                             │
│   lv_scale_section_t * sec1, * sec2, * sec3;                │
│   sec1 = lv_scale_add_section(scale);                       │
│   lv_scale_section_set_range(sec1, -10, 10);                │
│   lv_scale_section_set_style(sec1, LV_PART_INDICATOR, &s);  │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

***

### 3. ฟังก์ชันสำคัญ (API Reference)

#### 3.1 Scale Creation & Range

<table><thead><tr><th width="374.41546630859375">Function</th><th width="159.068115234375">Parameters</th><th>Description</th></tr></thead><tbody><tr><td><code>lv_scale_create(parent)</code></td><td>parent: lv_obj_t*</td><td>สร้าง scale widget</td></tr><tr><td><code>lv_scale_set_mode(scale, mode)</code></td><td>mode: lv_scale_mode_t</td><td>HORIZONTAL/VERTICAL/ROUND_INNER/ROUND_OUTER</td></tr><tr><td><code>lv_scale_set_range(scale, min, max)</code></td><td>min, max: int32_t</td><td>กำหนดช่วงค่า</td></tr><tr><td><code>lv_scale_set_total_tick_count(scale, cnt)</code></td><td>cnt: uint32_t</td><td>จำนวน tick ทั้งหมด</td></tr><tr><td><code>lv_scale_set_major_tick_every(scale, nth)</code></td><td>nth: uint32_t</td><td>ทุกกี่ tick เป็น major</td></tr></tbody></table>

#### 3.2 Tick Configuration

<table><thead><tr><th width="445.6512451171875">Function</th><th width="125.538330078125">Parameters</th><th>Description</th></tr></thead><tbody><tr><td><code>lv_scale_set_label_show(scale, show)</code></td><td>show: bool</td><td>แสดง/ซ่อน labels</td></tr><tr><td><code>lv_obj_set_style_length(scale, px, LV_PART_INDICATOR)</code></td><td>px: int32_t</td><td>ความยาว major tick</td></tr><tr><td><code>lv_obj_set_style_length(scale, px, LV_PART_ITEMS)</code></td><td>px: int32_t</td><td>ความยาว minor tick</td></tr></tbody></table>

#### 3.3 Round Scale Angles

<table><thead><tr><th width="337.757080078125">Function</th><th>Parameters</th><th>Description</th></tr></thead><tbody><tr><td><code>lv_scale_set_rotation(scale, deg)</code></td><td>deg: int32_t</td><td>มุมเริ่มต้น (เช่น 135)</td></tr><tr><td><code>lv_scale_set_angle_range(scale, deg)</code></td><td>deg: uint32_t</td><td>sweep angle (เช่น 270)</td></tr></tbody></table>

#### 3.4 Scale Sections (Color Zones)

<table><thead><tr><th width="400.19677734375">Function</th><th width="182.9361572265625">Parameters</th><th>Description</th></tr></thead><tbody><tr><td><code>lv_scale_add_section(scale)</code></td><td>-</td><td>สร้าง section ใหม่ (return pointer)</td></tr><tr><td><code>lv_scale_section_set_range(sec, min, max)</code></td><td>min, max: int32_t</td><td>กำหนดช่วงค่าของ section</td></tr><tr><td><code>lv_scale_section_set_style(sec, part, style)</code></td><td>part, style</td><td>กำหนด style สำหรับ section</td></tr></tbody></table>

***

### 4. โค้ดตัวอย่าง (Step-by-Step Code)

#### 4.1 Step 1: Global Variables และ Styles

```c
#include "lvgl.h"
#include <math.h>

/* ---- Widget Handles ---- */
static lv_obj_t * temp_scale;        /* Scale widget */
static lv_obj_t * needle_line;       /* Needle (lv_line) */
static lv_obj_t * value_label;       /* Center value label */
static lv_obj_t * status_label;      /* Status text */
static lv_timer_t * temp_timer;      /* Update timer */

/* ---- Needle points (ต้องเป็น static!) ---- */
static lv_point_precise_t needle_points[2];

/* ---- Section Styles ---- */
static lv_style_t style_cold;        /* Blue zone */
static lv_style_t style_normal;      /* Green zone */
static lv_style_t style_hot;         /* Red zone */

/* ---- Constants ---- */
#define TEMP_MIN        (-10)
#define TEMP_MAX        50
#define SCALE_SIZE      200           /* ขนาด scale (pixels) */
#define NEEDLE_LENGTH   75            /* ความยาวเข็ม */
```

#### 4.2 Step 2: Initialize Section Styles

```c
/*
 * init_section_styles() - สร้าง style สำหรับแต่ละ color zone
 *
 * ต้องเรียกก่อนสร้าง scale sections
 */
static void init_section_styles(void)
{
    /* Cold zone: Blue */
    lv_style_init(&style_cold);
    lv_style_set_arc_color(&style_cold,
                            lv_palette_main(LV_PALETTE_BLUE));
    lv_style_set_line_color(&style_cold,
                             lv_palette_main(LV_PALETTE_BLUE));
    lv_style_set_arc_width(&style_cold, 6);

    /* Normal zone: Green */
    lv_style_init(&style_normal);
    lv_style_set_arc_color(&style_normal,
                            lv_palette_main(LV_PALETTE_GREEN));
    lv_style_set_line_color(&style_normal,
                             lv_palette_main(LV_PALETTE_GREEN));
    lv_style_set_arc_width(&style_normal, 6);

    /* Hot zone: Red */
    lv_style_init(&style_hot);
    lv_style_set_arc_color(&style_hot,
                            lv_palette_main(LV_PALETTE_RED));
    lv_style_set_line_color(&style_hot,
                             lv_palette_main(LV_PALETTE_RED));
    lv_style_set_arc_width(&style_hot, 6);
}
```

#### 4.3 Step 3: Needle Update Function

```c
/*
 * update_needle_position() - คำนวณตำแหน่งเข็มจากค่า temperature
 *
 * มุมเข็ม = rotation + (value - min) / (max - min) * angle_range
 * rotation = 135, angle_range = 270
 */
static void update_needle_position(int32_t temp)
{
    /* Clamp to range */
    if (temp < TEMP_MIN) temp = TEMP_MIN;
    if (temp > TEMP_MAX) temp = TEMP_MAX;

    /* คำนวณ normalized position (0.0 to 1.0) */
    float normalized = (float)(temp - TEMP_MIN) /
                       (float)(TEMP_MAX - TEMP_MIN);

    /* คำนวณมุม (degrees) */
    float angle_deg = 135.0f + normalized * 270.0f;

    /* แปลง degrees to radians */
    float angle_rad = angle_deg * 3.14159f / 180.0f;

    /* จุดศูนย์กลางของ scale (relative to screen) */
    int32_t cx = 160;  /* ตรงกลางจอ */
    int32_t cy = 125;

    /* คำนวณ endpoint ของเข็ม */
    needle_points[0].x = cx;
    needle_points[0].y = cy;
    needle_points[1].x = cx + (int32_t)(NEEDLE_LENGTH * cosf(angle_rad));
    needle_points[1].y = cy + (int32_t)(NEEDLE_LENGTH * sinf(angle_rad));

    /* อัพเดท line widget */
    lv_line_set_points(needle_line, needle_points, 2);
}
```

#### 4.4 Step 4: Timer Callback

```c
/*
 * temp_timer_cb() - อัพเดทอุณหภูมิทุก 300ms
 */
static void temp_timer_cb(lv_timer_t * timer)
{
    (void)timer;

    /* จำลองอุณหภูมิ */
    static uint32_t tick = 0;
    tick++;

    float t = (float)tick * 0.02f;
    int32_t temp = 20 + (int32_t)(25.0f * sinf(t));
    temp += (lv_rand(0, 4) - 2);   /* noise +/- 2 */

    if (temp < TEMP_MIN) temp = TEMP_MIN;
    if (temp > TEMP_MAX)  temp = TEMP_MAX;

    /* อัพเดท needle */
    update_needle_position(temp);

    /* อัพเดท value label */
    lv_label_set_text_fmt(value_label, "%d degC", (int)temp);

    /* อัพเดทสีตัวเลขและ status */
    lv_color_t color;
    const char * status;

    if (temp <= 10) {
        color = lv_palette_main(LV_PALETTE_BLUE);
        status = "COLD";
    } else if (temp <= 35) {
        color = lv_palette_main(LV_PALETTE_GREEN);
        status = "NORMAL";
    } else {
        color = lv_palette_main(LV_PALETTE_RED);
        status = "HOT!";
    }

    lv_obj_set_style_text_color(value_label, color, 0);
    lv_label_set_text(status_label, status);
    lv_obj_set_style_text_color(status_label, color, 0);
}
```

#### 4.5 Step 5: Main Function - สร้าง Gauge UI

```c
void part2_ex4_scale_temperature(void)
{
    /* ---- Initialize styles ---- */
    init_section_styles();

    /* ---- Background ---- */
    lv_obj_set_style_bg_color(lv_screen_active(),
                               lv_color_hex(0x0f0f23), 0);

    /* ---- Title ---- */
    lv_obj_t * title = lv_label_create(lv_screen_active());
    lv_label_set_text(title, "Temperature Gauge");
    lv_obj_set_style_text_color(title, lv_color_hex(0x00d4ff), 0);
    lv_obj_set_style_text_font(title, &lv_font_montserrat_24, 0);
    lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 5);

    /* ---- Scale Widget ---- */
    temp_scale = lv_scale_create(lv_screen_active());
    lv_obj_set_size(temp_scale, SCALE_SIZE, SCALE_SIZE);
    lv_obj_align(temp_scale, LV_ALIGN_CENTER, 0, 0);

    /* Round mode (gauge) */
    lv_scale_set_mode(temp_scale, LV_SCALE_MODE_ROUND_OUTER);
    lv_scale_set_range(temp_scale, TEMP_MIN, TEMP_MAX);

    /* Angle: 270-degree sweep เริ่มจากล่างซ้าย */
    lv_scale_set_rotation(temp_scale, 135);
    lv_scale_set_angle_range(temp_scale, 270);

    /* Tick configuration */
    lv_scale_set_total_tick_count(temp_scale, 31);    /* 31 ticks */
    lv_scale_set_major_tick_every(temp_scale, 5);     /* ทุก 5 ticks = major */
    lv_scale_set_label_show(temp_scale, true);

    /* Tick styling - major */
    lv_obj_set_style_length(temp_scale, 12, LV_PART_INDICATOR);
    lv_obj_set_style_line_width(temp_scale, 2, LV_PART_INDICATOR);
    lv_obj_set_style_line_color(temp_scale,
                                 lv_color_hex(0xcccccc), LV_PART_INDICATOR);

    /* Tick styling - minor */
    lv_obj_set_style_length(temp_scale, 6, LV_PART_ITEMS);
    lv_obj_set_style_line_width(temp_scale, 1, LV_PART_ITEMS);
    lv_obj_set_style_line_color(temp_scale,
                                 lv_color_hex(0x666666), LV_PART_ITEMS);

    /* Label styling */
    lv_obj_set_style_text_color(temp_scale,
                                 lv_color_hex(0xaaaaaa), LV_PART_INDICATOR);

    /* Main arc (background track) */
    lv_obj_set_style_arc_color(temp_scale,
                                lv_color_hex(0x333344), LV_PART_MAIN);
    lv_obj_set_style_arc_width(temp_scale, 4, LV_PART_MAIN);

    /* ---- Color Sections ---- */

    /* Section 1: Cold (-10 to 10) - Blue */
    lv_scale_section_t * sec_cold = lv_scale_add_section(temp_scale);
    lv_scale_section_set_range(sec_cold, TEMP_MIN, 10);
    lv_scale_section_set_style(sec_cold, LV_PART_MAIN, &style_cold);
    lv_scale_section_set_style(sec_cold, LV_PART_INDICATOR, &style_cold);
    lv_scale_section_set_style(sec_cold, LV_PART_ITEMS, &style_cold);

    /* Section 2: Normal (10 to 35) - Green */
    lv_scale_section_t * sec_normal = lv_scale_add_section(temp_scale);
    lv_scale_section_set_range(sec_normal, 10, 35);
    lv_scale_section_set_style(sec_normal, LV_PART_MAIN, &style_normal);
    lv_scale_section_set_style(sec_normal, LV_PART_INDICATOR, &style_normal);
    lv_scale_section_set_style(sec_normal, LV_PART_ITEMS, &style_normal);

    /* Section 3: Hot (35 to 50) - Red */
    lv_scale_section_t * sec_hot = lv_scale_add_section(temp_scale);
    lv_scale_section_set_range(sec_hot, 35, TEMP_MAX);
    lv_scale_section_set_style(sec_hot, LV_PART_MAIN, &style_hot);
    lv_scale_section_set_style(sec_hot, LV_PART_INDICATOR, &style_hot);
    lv_scale_section_set_style(sec_hot, LV_PART_ITEMS, &style_hot);

    /* ---- Needle Line ---- */
    needle_line = lv_line_create(lv_screen_active());
    lv_obj_set_style_line_width(needle_line, 3, 0);
    lv_obj_set_style_line_color(needle_line,
                                 lv_color_hex(0xff8800), 0);
    lv_obj_set_style_line_rounded(needle_line, true, 0);

    /* ตำแหน่งเริ่มต้น (20 degC) */
    update_needle_position(20);

    /* ---- Center pivot dot ---- */
    lv_obj_t * pivot = lv_obj_create(lv_screen_active());
    lv_obj_set_size(pivot, 10, 10);
    lv_obj_set_style_radius(pivot, LV_RADIUS_CIRCLE, 0);
    lv_obj_set_style_bg_color(pivot, lv_color_hex(0xff8800), 0);
    lv_obj_set_style_border_width(pivot, 0, 0);
    lv_obj_align(pivot, LV_ALIGN_CENTER, 0, 0);

    /* ---- Value Label ---- */
    value_label = lv_label_create(lv_screen_active());
    lv_label_set_text(value_label, "20 degC");
    lv_obj_set_style_text_color(value_label,
                                 lv_palette_main(LV_PALETTE_GREEN), 0);
    lv_obj_set_style_text_font(value_label, &lv_font_montserrat_24, 0);
    lv_obj_align(value_label, LV_ALIGN_CENTER, 0, 40);

    /* ---- Status Label ---- */
    status_label = lv_label_create(lv_screen_active());
    lv_label_set_text(status_label, "NORMAL");
    lv_obj_set_style_text_color(status_label,
                                 lv_palette_main(LV_PALETTE_GREEN), 0);
    lv_obj_align(status_label, LV_ALIGN_BOTTOM_MID, 0, -8);

    /* ---- Timer: อัพเดททุก 300ms ---- */
    temp_timer = lv_timer_create(temp_timer_cb, 300, NULL);
}
```

#### 4.6 UI Layout

```
┌──────────────────────────────────────┐
│         Temperature Gauge            │
│                                      │
│       -10    10     35    50         │
│        ╭──┬──┬──┬──┬──┬──╮           │
│       ╱BLUE │GREEN │ RED  ╲          │
│      │ ║║║║ │║║║║║ │║║║║║  │         │
│      │      │   ╱  │       │         │
│      │      │  ●───│       │         │
│       ╲ ║║║║│║║║║║ │║║║║  ╱          │
│        ╰──┴──┴──┴──┴──┴──╯           │
│                                      │
│            20 degC                   │
│            NORMAL                    │
└──────────────────────────────────────┘
```

***

### 5. องค์ความรู้และเทคนิค&#x20;

#### 5.1 Scale Modes Comparison

| Mode         | Shape             | Use Case      | Example             |
| ------------ | ----------------- | ------------- | ------------------- |
| HORIZONTAL   | แนวนอน            | Ruler, level  | Signal strength bar |
| VERTICAL     | แนวตั้ง           | Thermometer   | Mercury thermometer |
| ROUND\_OUTER | วงกลม (ticks นอก) | Gauge มาตรฐาน | Speedometer         |
| ROUND\_INNER | วงกลม (ticks ใน)  | Gauge compact | Watch dial          |

#### 5.2 Tick Count Formula

```c
/*
 * การคำนวณ tick count:
 * - Range: min to max
 * - total_tick_count = (ตัวเลข major tick ทั้งหมด - 1) * minor_per_major + 1
 *
 * ตัวอย่าง: Range -10 to 50, major ทุก 10 degrees
 * - Major labels: -10, 0, 10, 20, 30, 40, 50 = 7 labels
 * - Minor between majors: 4 (ขีดเล็กระหว่าง major)
 * - major_tick_every = 5 (ทุก 5 minor ticks เป็น 1 major)
 * - total = (7-1) * 5 + 1 = 31 ticks
 */
lv_scale_set_total_tick_count(scale, 31);
lv_scale_set_major_tick_every(scale, 5);
```

#### 5.3 Needle Angle Calculation

```c
/*
 * สูตรคำนวณมุมเข็ม (สำหรับ 270-degree gauge, rotation 135):
 *
 * angle = start_rotation + (value - min) / (max - min) * sweep
 *
 * start_rotation = 135 degrees
 * sweep = 270 degrees
 *
 * ตัวอย่าง: temp = 20, range -10 to 50
 * normalized = (20 - (-10)) / (50 - (-10)) = 30/60 = 0.5
 * angle = 135 + 0.5 * 270 = 270 degrees
 * → เข็มชี้ตรงกลาง (12 o'clock position)
 */
```

#### 5.4 Section Style Pattern

```c
/* Pattern: สร้าง style แยกสำหรับแต่ละ section
 *
 * สำคัญ: style ต้องเป็น static หรือ global
 * เพราะ LVGL reference ไปที่ style pointer ตลอดเวลา
 */
static lv_style_t my_style;         /* ถูกต้อง: static */
lv_style_init(&my_style);
lv_style_set_arc_color(&my_style, lv_palette_main(LV_PALETTE_RED));
lv_style_set_line_color(&my_style, lv_palette_main(LV_PALETTE_RED));

/* ห้าม: local style ใน function */
void bad_example(void) {
    lv_style_t local_style;          /* ผิด: หายเมื่อ function จบ */
    lv_style_init(&local_style);     /* scale จะ crash ทีหลัง */
}
```

#### 5.5 Line Points ต้อง Static

```c
/* สำคัญมาก: lv_line ต้องการ static point array
 * เพราะ LVGL ไม่ copy ข้อมูล แค่เก็บ pointer */

static lv_point_precise_t points[2];    /* ถูกต้อง: static */
points[0].x = 100; points[0].y = 100;
points[1].x = 200; points[1].y = 50;
lv_line_set_points(line, points, 2);

/* ห้าม: local array */
void bad_needle(void) {
    lv_point_precise_t pts[2];     /* ผิด: หายเมื่อ function จบ */
    pts[0].x = 100; ...
    lv_line_set_points(line, pts, 2);  /* เข็มจะแสดงผิด/crash */
}
```

#### 5.6 Multiple Scales ซ้อนกัน

```c
/* สร้าง dual scale สำหรับ Temperature + Humidity */
lv_obj_t * outer = lv_scale_create(lv_screen_active());
lv_obj_set_size(outer, 200, 200);
lv_scale_set_mode(outer, LV_SCALE_MODE_ROUND_OUTER);
lv_scale_set_range(outer, 0, 50);    /* Temp degC */

lv_obj_t * inner = lv_scale_create(lv_screen_active());
lv_obj_set_size(inner, 160, 160);    /* เล็กกว่า */
lv_scale_set_mode(inner, LV_SCALE_MODE_ROUND_INNER);
lv_scale_set_range(inner, 0, 100);   /* Humidity % */

/* จัดให้อยู่ตรงกลางเดียวกัน */
lv_obj_align(outer, LV_ALIGN_CENTER, 0, 0);
lv_obj_align(inner, LV_ALIGN_CENTER, 0, 0);
```

***

### 6. แบบฝึกหัด (Exercises)

#### Exercise 1: Pressure Gauge (0-100 PSI with 3 Color Zones)

สร้าง Pressure Gauge สำหรับ Industrial Monitoring:

**Requirements:**

* Scale mode: ROUND\_OUTER, 270-degree sweep
* Range: 0-100 PSI
* **3 Color zones:**
  * 0-30 PSI: สีเขียว (Normal operating pressure)
  * 31-70 PSI: สีเหลือง (Elevated pressure)
  * 71-100 PSI: สีแดง (Critical! Over-pressure warning)
* Needle ชี้ค่าปัจจุบัน
* Center label: "XX PSI"
* Status label: "Normal" / "Warning" / "CRITICAL!"
* Major tick ทุก 10 PSI (0, 10, 20, ..., 100)
* Timer จำลองค่า pressure ที่เปลี่ยนแปลง

```
┌──────────────────────────────────────┐
│        Pressure Gauge                │
│                                      │
│        0   20  40  60  80 100        │
│        ╭──┬──┬──┬──┬──┬──╮           │
│       ╱GREEN│YELLOW│ RED  ╲          │
│      │ ║║║║ │║║║║║ │║║║║║  │         │
│      │      │  ╱   │       │         │
│      │      │ ●────│       │         │
│       ╲ ║║║║│║║║║║ │║║║║  ╱          │
│        ╰──┴──┴──┴──┴──┴──╯           │
│                                      │
│           45 PSI                     │
│           Warning                    │
└──────────────────────────────────────┘
```

**Hints:**

* total\_tick\_count = 51 (0 ถึง 100, ทุก 2 PSI)
* major\_tick\_every = 5 (ทุก 10 PSI)
* ใช้ pattern จาก Section 4.3 สำหรับ needle calculation

***

#### Exercise 2: Combined Temperature + Humidity Display with Dual Scales

สร้างจอแสดงผล Temperature และ Humidity แบบ dual gauge:

**Requirements:**

* **Gauge 1** (ซ้าย): Temperature Scale
  * Mode: ROUND\_OUTER, size 130x130
  * Range: -10 to 50 degC
  * Sections: Blue (cold), Green (normal), Red (hot)
  * Needle + center value
* **Gauge 2** (ขวา): Humidity Scale
  * Mode: ROUND\_OUTER, size 130x130
  * Range: 0-100 %RH
  * Sections: Red (dry), Green (normal), Blue (humid)
  * Needle + center value
* Timer จำลองค่าที่เปลี่ยนสัมพันธ์กัน (temp สูง → humidity ต่ำ)
* Label ด้านล่างแสดง "Comfort Index" (Good/Fair/Poor)

```
┌──────────────────────────────────────┐
│   Temperature & Humidity Monitor     │
│                                      │
│   ╭──────╮           ╭──────╮        │
│  ╱  25    ╲         ╱  60    ╲       │
│ │  degC    │       │  %RH     │      │
│  ╲  ●──   ╱         ╲  ●──   ╱       │
│   ╰──────╯           ╰──────╯        │
│     TEMP               HUMID         │
│                                      │
│     Comfort Index: Good              │
└──────────────────────────────────────┘
```

**Hints:**

* ใช้ `lv_obj_align()` จัดวางซ้าย-ขวา
* แต่ละ gauge มี needle\_points แยกกัน (static array แยก)
* Comfort Index: Temp 20-26 + Humid 40-60 = "Good"

***

### 7. References

* [LVGL Scale](https://docs.lvgl.io/9.2/widgets/scale.html)
* [lv\_example\_scale\_4.c](https://github.com/lvgl/lvgl/blob/release/v9.2/examples/widgets/scale/lv_example_scale_4.c)

***


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.aic-eec.com/interfacing-with-infineon-psoc-tm-edge/hmi-development/sensor-to-hmi-display/ux-ui-workshops/scale-temperature.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
