Perubahan Full

This commit is contained in:
Nararga Maulana_TKJ2 2024-07-24 23:37:00 +07:00
parent fb2a93889e
commit 773cc55ea3
49 changed files with 727 additions and 196 deletions

BIN
Store.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

View File

@ -22,8 +22,14 @@ if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
namespace "com.example.beta_app1"
namespace "com.nutrify.app"
compileSdk flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
@ -42,7 +48,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.beta_app1"
applicationId "com.nutrify.app"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion
@ -51,13 +57,17 @@ android {
versionName flutterVersionName
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
minifyEnabled true
shrinkResources true
signingConfig signingConfigs.release
}
}
}

View File

@ -6,7 +6,7 @@
<application
android:label="Nutrify"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
android:icon="@mipmap/launcher_icon">
<activity
android:name=".MainActivity"
android:exported="true"

View File

@ -1,4 +1,4 @@
package com.example.beta_app1
package com.nutrify.app
import io.flutter.embedding.android.FlutterActivity

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 MiB

BIN
images/nutrify.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -427,7 +427,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
@ -484,7 +484,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 978 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 B

After

Width:  |  Height:  |  Size: 654 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 B

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 978 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 762 B

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -34,7 +34,7 @@ class _LoginPageState extends State<LoginPage> {
final prefs = await SharedPreferences.getInstance();
String mqttServerIp =
prefs.getString('mqtt_server_ip') ?? '192.168.183.153';
prefs.getString('mqtt_server_ip') ?? '192.168.182.153';
String url = 'http://$mqttServerIp/test_api/login.php';
final response = await http.post(
@ -128,7 +128,7 @@ class _LoginPageState extends State<LoginPage> {
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
"images/nature.gif",
"images/nutrify.png",
height: 200,
width: 200,
),
@ -216,31 +216,41 @@ class _LoginPageState extends State<LoginPage> {
),
child: const Text(
'Login',
style: TextStyle(color: Colors.white),
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () {
const SizedBox(height: 25),
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Belum memiliki akun?',
style: TextStyle(
color: Colors.black,
fontSize: 14.0,
),
),
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RegisterPage()),
builder: (context) => RegisterPage(),
),
);
},
style: ElevatedButton.styleFrom(
backgroundColor:
const Color.fromARGB(255, 255, 255, 255),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
padding: const EdgeInsets.symmetric(vertical: 16.0),
minimumSize: const Size(double.infinity, 50),
),
child: const Text(
'Register',
' Register',
style: TextStyle(
color: Color.fromARGB(166, 26, 21, 21)),
color: Colors.red,
fontSize: 14.0,
),
),
),
],
),
),
],
@ -259,7 +269,7 @@ class _LoginPageState extends State<LoginPage> {
const Text(
"@2024",
style: TextStyle(color: Colors.black, fontSize: 10.0),
)
),
],
),
),

View File

@ -1,3 +1,4 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'login.dart';
@ -53,21 +54,24 @@ class _RegisterPageState extends State<RegisterPage> {
});
}
// Validasi fullname (opsional)
final prefs = await SharedPreferences.getInstance();
String mqttServerIp = prefs.getString('mqtt_server_ip') ?? '192.168.0.1';
String mqttServerIp =
prefs.getString('mqtt_server_ip') ?? '192.168.182.153';
String url = 'http://$mqttServerIp/test_api/register.php';
final response = await http.post(
Uri.parse(url),
body: {
headers: {"Content-Type": "application/json"},
body: jsonEncode({
"username": username,
"password": password,
"fullname": fullname,
},
}),
);
if (response.statusCode == 200) {
final responseData = jsonDecode(response.body);
if (responseData['status'] == 'success') {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Akun berhasil dibuat'),
@ -81,7 +85,24 @@ class _RegisterPageState extends State<RegisterPage> {
);
} else {
setState(() {
// Handle error
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(responseData['message']),
duration: Duration(seconds: 2),
backgroundColor: Colors.red,
),
);
});
}
} else {
setState(() {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Failed to register user'),
duration: Duration(seconds: 2),
backgroundColor: Colors.red,
),
);
});
}
}
@ -89,23 +110,22 @@ class _RegisterPageState extends State<RegisterPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Halaman Registrasi'),
),
body: SingleChildScrollView(
backgroundColor: Colors.white,
body: Center(
child: SingleChildScrollView(
child: Center(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10.0),
child:
Image.asset("images/nature.gif", height: 200, width: 200),
Image.asset(
"images/nutrify.png",
height: 200,
width: 200,
),
const SizedBox(
height: 10,
height: 20,
),
Card(
shape: RoundedRectangleBorder(
@ -224,23 +244,78 @@ class _RegisterPageState extends State<RegisterPage> {
ElevatedButton(
onPressed: registerUser,
style: ElevatedButton.styleFrom(
backgroundColor: Color.fromARGB(255, 221, 41, 41),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
padding: const EdgeInsets.symmetric(vertical: 16.0),
padding:
const EdgeInsets.symmetric(vertical: 16.0),
minimumSize: const Size(double.infinity, 50),
),
child: const Text('Daftar'),
child: const Text(
'Daftar',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Sudah memiliki akun?',
style: TextStyle(
color: Colors.black,
fontSize: 14.0,
),
),
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const LoginPage(),
),
);
},
child: const Text(
' Masuk',
style: TextStyle(
color: Colors.green,
fontSize: 14.0,
fontWeight: FontWeight.bold,
),
),
),
],
),
],
),
),
),
const SizedBox(height: 20),
const Text(
"Apps Made For",
style: TextStyle(color: Colors.black, fontSize: 10),
),
const Text(
"Nutrient Hydroponic Control",
style: TextStyle(color: Colors.black, fontSize: 10.0),
),
const Text(
"@2024",
style: TextStyle(color: Colors.black, fontSize: 10.0),
),
],
),
),
),
),
),
);
}
}

View File

@ -258,8 +258,8 @@ class _ChartsSectionState extends State<ChartsSection> {
),
primaryYAxis: NumericAxis(
minimum: 0,
maximum: 20,
interval: 5,
maximum: 1000,
interval: 200,
majorGridLines: MajorGridLines(width: 0.5, color: Colors.grey[300]),
axisLine: AxisLine(width: 0),
labelStyle: TextStyle(color: Colors.grey[700], fontSize: 12),

View File

@ -33,7 +33,7 @@ class _SplashScreenState extends State<SplashScreen> {
backgroundColor:
Colors.white, // Ubah sesuai warna latar belakang yang diinginkan
body: Center(
child: Image.asset('images/nature.gif',
child: Image.asset('images/nutrify.png',
width: 200,
height:
200), // Pastikan untuk menambahkan logo Anda di folder assets

View File

@ -7,7 +7,7 @@ project(runner LANGUAGES CXX)
set(BINARY_NAME "beta_app1")
# The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
set(APPLICATION_ID "com.example.beta_app1")
set(APPLICATION_ID "com.nutrify.app")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.

View File

@ -1,6 +1,14 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
archive:
dependency: transitive
description:
name: archive
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
url: "https://pub.dev"
source: hosted
version: "3.6.1"
args:
dependency: transitive
description:
@ -65,6 +73,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.1"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
url: "https://pub.dev"
source: hosted
version: "2.0.3"
cli_util:
dependency: transitive
description:
name: cli_util
sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19
url: "https://pub.dev"
source: hosted
version: "0.4.1"
clock:
dependency: transitive
description:
@ -166,6 +190,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.3.2"
flutter_launcher_icons:
dependency: "direct main"
description:
name: flutter_launcher_icons
sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea"
url: "https://pub.dev"
source: hosted
version: "0.13.1"
flutter_lints:
dependency: "direct dev"
description:
@ -232,6 +264,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.2"
image:
dependency: transitive
description:
name: image
sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8"
url: "https://pub.dev"
source: hosted
version: "4.2.0"
intl:
dependency: transitive
description:
@ -240,6 +280,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.18.1"
json_annotation:
dependency: transitive
description:
name: json_annotation
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
url: "https://pub.dev"
source: hosted
version: "4.9.0"
leak_tracker:
dependency: transitive
description:
@ -661,6 +709,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.5.0"
yaml:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.3.4 <4.0.0"
flutter: ">=3.19.0"

View File

@ -42,6 +42,7 @@ dependencies:
liquid_progress_indicator_v2: ^0.5.0
cached_network_image: ^3.3.1
flutter_local_notifications: ^17.2.1+2
flutter_launcher_icons: "^0.13.1"
dev_dependencies:
flutter_test:
@ -54,6 +55,12 @@ dev_dependencies:
# rules and activating additional ones.
flutter_lints: ^4.0.0
flutter_launcher_icons:
android: "launcher_icon"
ios: true
image_path: "images/nutrify.png"
min_sdk_android: 21 # android min sdk min:16, default 21
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
@ -66,12 +73,10 @@ flutter:
# To add assets to your application, add an assets section, like this:
assets:
- images/ahri_coven.gif
- images/ahri_ori.gif
- images/ahri_icon.jpg
- images/nature.gif
- images/arga.jpg
- images/hidroponik.png
- images/nutrify.png
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware

93
test_api/data_chart.php Normal file
View File

@ -0,0 +1,93 @@
<?php
// Koneksi ke database
$conn = mysqli_connect("localhost", "root", "", "tugas_akhir");
// Periksa koneksi
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// Mendapatkan tanggal mulai dan akhir dari permintaan
$startDate = isset($_GET['start_date']) ? $_GET['start_date'] : null;
$endDate = isset($_GET['end_date']) ? $_GET['end_date'] : null;
// Menyiapkan klausa WHERE untuk filter tanggal
$whereClause = "";
if ($startDate && $endDate) {
$whereClause = " WHERE timestamp BETWEEN '$startDate' AND '$endDate'";
}
$data = array();
$data1 = array();
$data2 = array();
$data3 = array();
// Mengambil data dari tabel tb_waterflow1 termasuk kolom timestamp dan id
$sql = "SELECT id_wf1 as x, timestamp, waterflow1_value as y1 FROM tb_waterflow1 $whereClause";
$result = $conn->query($sql);
if ($result) {
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$data[] = $row;
}
}
} else {
echo "Error: " . $conn->error;
}
// Mengambil data dari tabel tb_waterflow2 termasuk kolom timestamp dan id
$sql1 = "SELECT id_wf2 as x, timestamp, waterflow2_value as y2 FROM tb_waterflow2 $whereClause";
$result1 = $conn->query($sql1);
if ($result1) {
if ($result1->num_rows > 0) {
while ($row = $result1->fetch_assoc()) {
$data1[] = $row;
}
}
} else {
echo "Error: " . $conn->error;
}
// Mengambil data dari tabel tb_ppm termasuk kolom timestamp dan id
$sql2 = "SELECT id_ppm as x, timestamp, ppm_value as y3 FROM tb_ppm $whereClause";
$result2 = $conn->query($sql2);
if ($result2) {
if ($result2->num_rows > 0) {
while ($row = $result2->fetch_assoc()) {
$data2[] = $row;
}
}
} else {
echo "Error: " . $conn->error;
}
// Mengambil data dari tabel tb_waterlevel termasuk kolom timestamp dan id
$sql3 = "SELECT id_wl as x, timestamp, ultrasonic_value as y FROM tb_waterlevel $whereClause";
$result3 = $conn->query($sql3);
if ($result3) {
if ($result3->num_rows > 0) {
while ($row = $result3->fetch_assoc()) {
$data3[] = $row;
}
}
} else {
echo "Error: " . $conn->error;
}
// Tutup koneksi
$conn->close();
// Mengatur header untuk respon JSON
header('Content-Type: application/json');
// Mengirimkan data sebagai JSON
echo json_encode(array(
'tb_waterflow1' => $data,
'tb_waterflow2' => $data1,
'tb_ppm' => $data2,
'tb_waterlevel' => $data3
));

42
test_api/data_plant.php Normal file
View File

@ -0,0 +1,42 @@
<?php
// Koneksi ke database MySQL
$conn = mysqli_connect("localhost", "root", "", "tugas_akhir");
// Periksa koneksi
if (!$conn) {
die("Koneksi ke database gagal: " . mysqli_connect_error());
}
// Kueri untuk mengambil data tanaman
$sql = "SELECT id_plant, title, desk, kategori, img, date FROM tb_plant";
// Jalankan kueri SQL
$result = mysqli_query($conn, $sql);
// Inisialisasi array untuk menyimpan data tanaman
$plants = array();
// Base URL untuk gambar (sesuaikan dengan alamat server Anda)
$base_url = 'http://' . $_SERVER['SERVER_ADDR'] . '/Upload/uploads/';
// Periksa apakah kueri berhasil dijalankan
if (mysqli_num_rows($result) > 0) {
// Ambil setiap baris data tanaman dan tambahkan ke array
while ($row = mysqli_fetch_assoc($result)) {
// Tambahkan URL penuh untuk gambar
$row['img'] = $base_url . $row['img'];
$plants[] = $row;
}
}
// Konversi array ke format JSON
$json_response = json_encode($plants);
// Set header untuk respon JSON
header('Content-Type: application/json');
// Tampilkan respon JSON
echo $json_response;
// Tutup koneksi database
mysqli_close($conn);

27
test_api/dbconnection.php Normal file
View File

@ -0,0 +1,27 @@
<!-- <?php
function dbconnection()
{
$con = mysqli_connect("localhost", "root", "", "tugas_akhir");
return $con;
}
?> -->
<!-- <?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "tugas_akhir";
// Create connection
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
?> -->
<?php
$con = mysqli_connect('localhost', 'root', '', 'tugas_akhir') or die('tidak terkoneksi');
?>

43
test_api/get_data.php Normal file
View File

@ -0,0 +1,43 @@
<?php
// Koneksi ke database MySQL
$conn = mysqli_connect("localhost", "root", "", "tugas_akhir");
// Periksa koneksi
if (!$conn) {
die("Koneksi ke database gagal: " . mysqli_connect_error());
}
// Periksa apakah parameter username diberikan
if (isset($_GET['username'])) {
$username = $_GET['username'];
$sql = "SELECT username, fullname FROM tb_login WHERE username = '$username'";
} else {
// Tidak ada username, kembalikan semua data pengguna
$sql = "SELECT username, fullname FROM tb_login";
}
// Jalankan kueri SQL
$result = mysqli_query($conn, $sql);
// Inisialisasi array untuk menyimpan data pengguna
$users = array();
// Periksa apakah kueri berhasil dijalankan
if (mysqli_num_rows($result) > 0) {
// Ambil setiap baris data pengguna dan tambahkan ke array
while ($row = mysqli_fetch_assoc($result)) {
$users[] = $row;
}
}
// Konversi array ke format JSON
$json_response = json_encode($users);
// Set header untuk respon JSON
header('Content-Type: application/json');
// Tampilkan respon JSON
echo $json_response;
// Tutup koneksi database
mysqli_close($conn);

44
test_api/login.php Normal file
View File

@ -0,0 +1,44 @@
<?php
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
$conn = new mysqli("localhost", "root", "", "tugas_akhir");
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$username = $_POST['username'];
$password = $_POST['password'];
// Query untuk mengambil hash password berdasarkan username
$query = $conn->prepare("SELECT * FROM tb_login WHERE username=?");
$query->bind_param("s", $username);
$query->execute();
$result = $query->get_result();
if ($result->num_rows == 1) {
$data = $result->fetch_assoc();
$hashedPassword = $data['password'];
// Verifikasi password
if (password_verify($password, $hashedPassword)) {
$token = bin2hex(random_bytes(10)); // Generate a random token with 10 bytes
// Simpan token ke database
$updateQuery = $conn->prepare("UPDATE tb_login SET token=? WHERE username=?");
$updateQuery->bind_param("ss", $token, $username);
if ($updateQuery->execute()) {
$data['token'] = $token;
echo json_encode(array("success" => true, "data" => $data));
} else {
echo json_encode(array("success" => false, "message" => "Failed to update token"));
}
} else {
echo json_encode(array("success" => false, "message" => "Invalid username or password."));
}
} else {
echo json_encode(array("success" => false, "message" => "Invalid username or password."));
}
$conn->close();

21
test_api/logout.php Normal file
View File

@ -0,0 +1,21 @@
<?php
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
$conn = new mysqli("localhost", "root", "", "tugas_akhir");
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$token = $_POST['token'];
$query = "UPDATE tb_login SET token='' WHERE token='$token'";
if (mysqli_query($conn, $query)) {
echo json_encode(["success" => true]);
} else {
echo json_encode(["error" => "Failed to update token."]);
}
$conn->close();

57
test_api/register.php Normal file
View File

@ -0,0 +1,57 @@
<?php
header("Content-Type: application/json; charset=UTF-8");
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "tugas_akhir";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
echo json_encode(array("status" => "error", "message" => "Connection failed: " . $conn->connect_error));
exit();
}
// Get POST data
$data = json_decode(file_get_contents("php://input"), true);
$username = $data['username'];
$password = $data['password'];
$fullname = $data['fullname'];
// Validate input data
if (empty($username) || empty($password) || empty($fullname)) {
echo json_encode(array("status" => "error", "message" => "All fields are required."));
exit();
}
// Check if username already exists
$sql = "SELECT * FROM tb_login WHERE username = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $username);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
echo json_encode(array("status" => "error", "message" => "Username already exists."));
exit();
}
// Hash the password
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
// Insert new user
$sql = "INSERT INTO tb_login (username, password, fullname) VALUES (?, ?, ?)";
$stmt = $conn->prepare($sql);
$stmt->bind_param("sss", $username, $hashed_password, $fullname);
if ($stmt->execute()) {
echo json_encode(array("status" => "success", "message" => "Registration successful."));
} else {
echo json_encode(array("status" => "error", "message" => "Registration failed."));
}
// Close connections
$stmt->close();
$conn->close();

48
test_api/save_msg.php Normal file
View File

@ -0,0 +1,48 @@
<?php
header('Content-Type: application/json');
// Database connection
$host = 'localhost';
$db = 'tugas_akhir';
$user = 'root';
$pass = '';
$conn = new mysqli($host, $user, $pass, $db);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// Get JSON input
$input = file_get_contents('php://input');
$data = json_decode($input, true);
$topic = $data['topic'];
$value = $data['value'];
$speed = isset($data['speed']) ? $data['speed'] : null;
if ($topic == 'sensor/waterflow1') {
$stmt = $conn->prepare("INSERT INTO tb_waterflow1 (timestamp, waterflow1_value, waterflow1_speed) VALUES (NOW(), ?, ?)");
$stmt->bind_param("dd", $value, $speed);
} else if ($topic == 'sensor/waterflow2') {
$stmt = $conn->prepare("INSERT INTO tb_waterflow2 (timestamp, waterflow2_value, waterflow2_speed) VALUES (NOW(), ?, ?)");
$stmt->bind_param("dd", $value, $speed);
} else if ($topic == 'sensor/tds') {
$stmt = $conn->prepare("INSERT INTO tb_ppm (timestamp, ppm_value) VALUES (NOW(), ?)");
$stmt->bind_param("d", $value);
} else if ($topic == 'sensor/ultrasonic') {
$stmt = $conn->prepare("INSERT INTO tb_waterlevel (timestamp, ultrasonic_value) VALUES (NOW(), ?)");
$stmt->bind_param("d", $value);
} else {
echo json_encode(["status" => "error", "message" => "Unknown topic"]);
exit;
}
if ($stmt->execute()) {
echo json_encode(["status" => "success"]);
} else {
echo json_encode(["status" => "error", "message" => $stmt->error]);
}
$stmt->close();
$conn->close();

BIN
upload-keystore.jks Normal file

Binary file not shown.