Contiki OS and Python Server Socket Port

First, we need to create a C program that runs on Contiki OS. This program will establish a TCP/IP connection and exchange data using Contiki’s special operating system functions.

#include "contiki.h"
#include "net/rime/rime.h"

#include "net/rpl/rpl-private.h"
#include "sys/rtimer.h"
#include "net/ip/uip.h"

#include "lib/random.h"
#include <stdio.h>

#include "decreased-rank.h"

#define DEBUG DEBUG_PRINT
#include "net/ip/uip-debug.h"

#define DECREASED_RANK_PORT 4445
#define UIP_HTONS(n) (uint16_t)((((uint16_t) (n)) << 8) | (((uint16_t) (n)) >> 8))

#define PERIOD 20
#define SEND_INTERVAL   (PERIOD * CLOCK_SECOND) 

#include "net/ip/uip-debug.h"


/*-------------------------------------------------------------*/
PROCESS(udp_python_process, "Decreased Rank Attack Process");
AUTOSTART_PROCESSES(&udp_python_process);

/*-------------------------------------------------------------*/
void get_data_from_python_server(){
  char *str;

  if(uip_newdata()) {

    str = uip_appdata;
    str[uip_datalen()] = '\0';
    printf("DATA recv get_data_from_rcu '%s'\n", str);
  }
    
}

/*-------------------------------------------------------------
 * decreased_rank_attack_simulated_init
 */
void decreased_rank_attack_simulated_init()
{
    PRINTF("Decreased Rank Attack Process Started\n");

    process_start(&udp_python_process, NULL);

}

/*-------------------------------------------------------------
 *
 */
PROCESS_THREAD(rank_attack_process, ev, data)
{
  static uint8_t ret;
  static struct etimer et;
  static struct uip_udp_conn *client_conn = NULL;

  PROCESS_BEGIN();
  
    /* new connection with remote host */
  client_conn = udp_new(NULL, 0, NULL); 
  if(client_conn == NULL) {
    PRINTF("No UDP connection available, exiting the process!\n");
    PROCESS_EXIT();
  }
  udp_bind(client_conn, UIP_HTONS(DECREASED_RANK_PORT)); 

  printf("rank_attack_process()\n");

  while(1){
    PROCESS_YIELD();

    if(ev == tcpip_event){
      get_data_from_python_server();
    }

  }
  PROCESS_END();
}

/*-------------------------------------------------------------
 *
 */
void 
decreased_rank_process_init(int joined){
	decreased_rank_attack_simulated_init();
}

This C program will create a server in Contiki OS and listen for incoming data on a port defined as SERVER_PORT. It will process the incoming data with the tcpip_handler function and print it to the console.

import socket
            # Create ipv6 datagram socket
            sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
            # Allow own messages to be sent back (for local testing)
            sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, True)

            str_ip_pool = ip_addr
            find_node_to_end_node(matrix_neighbor, str(list_ip_addrs[i]))
            sock.sendto("hello world from JRC", (str_ip_pool, 4445))

First, the socket module is imported.

To create an IPv6 datagram socket, socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) is used. The AF_INET6 parameter specifies that we will be using IPv6 addressing, while the SOCK_DGRAM parameter specifies that we will be using the UDP protocol.

To allow our own messages to be sent back (for local testing), sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, True) is used. This enables loopback of multicast messages, allowing us to receive our own messages during local testing.

The variable str_ip_pool is assigned an IPv6 address.

A message is sent over UDP using sock.sendto("hello world from JRC", (str_ip_pool, 4445)). The message “hello world from JRC” is sent to the specified destination IP address (str_ip_pool) and port number (4445).

Explanation of UIP_HTONS() and other defined macros:

The UIP_HTONS(n) macro is used to convert a 16-bit value to network byte order. This swaps the bytes, converting the value from host byte order to big-endian format. The expression (((uint16_t) (n)) << 8) shifts the 16-bit value to the left by 8 bits, adding zero bits on the right. This moves the most significant byte to the leftmost 8 bits.

The expression (((uint16_t) (n)) >> 8) shifts the 16-bit value to the right by 8 bits, adding zero bits on the left. This moves the least significant byte to the rightmost 8 bits. Finally, these two expressions are combined using the | operator, resulting in a 16-bit value with its byte order swapped. The most significant byte and the least significant byte have swapped positions.

Şeker Hastalığı: Tanımı, Nedenleri ve Türleri

Şeker Hastalığı: Tanımı, Nedenleri ve Türleri

Günümüzde giderek artan bir sağlık sorunu olan şeker hastalığı (diyabet), vücudun kan şekeri seviyelerinin düzenlenmesinde sorun yaşandığında ortaya çıkan bir durumdur. İnsülin hormonunun yetersizliği veya etkinliğinin azalması sonucu kan şekerinin kontrol edilemez hale gelmesi, diyabetin temel belirtilerinden biridir. Pek çok insanın hayatını etkileyen bu hastalığın farklı türleri bulunmaktadır.  Tip 1, Tip 2 ve gestasyonel diyabet olmak üzere farklı türleri vardır.

1. Tip 1 Diyabet:

Tip 1 diyabet, genellikle çocukluk veya adolesan dönemlerinde başlayan otoimmün bir hastalıktır. Bağışıklık sistemi, pankreastaki beta hücrelerini hedef alır ve onları tahrip eder. Bu hücreler, vücutta insülin üretiminden sorumludur. İnsülinin eksikliği, kan şekerinin hücrelere taşınmasını engeller ve sonuç olarak kan şekerinin yükselmesine neden olur. Tip 1 diyabet hastaları, yaşamları boyunca günlük insülin enjeksiyonlarına veya insülin pompalarına ihtiyaç duyarlar.

2. Tip 2 Diyabet:

Tip 2 diyabet, genellikle ilerleyen yaşlarda ortaya çıkan ve en yaygın şeker hastalığı türüdür. Bu durumda, vücut hâlâ insülin üretir, ancak üretilen insülinin etkinliği azalır veya vücut hücreleri insüline karşı direnç geliştirir. Tip 2 diyabet genellikle obezite, hareketsiz yaşam tarzı, genetik yatkınlık ve yaşam tarzı faktörlerinin bir kombinasyonuyla ilişkilidir. İlk aşamalarda diyabetin kontrol altına alınması, sağlıklı bir diyet, egzersiz ve kilo kaybı gibi yaşam tarzı değişiklikleriyle mümkün olabilir. İlerleyen durumlarda, oral antidiyabetik ilaçlar veya insülin enjeksiyonları gerekebilir.

3. Gestasyonel Diyabet:

Gestasyonel diyabet, hamilelik sırasında beliren geçici bir diyabet türüdür. Hamilelik döneminde hormon seviyelerindeki değişiklikler, bazı kadınlarda insülin direncine neden olabilir. Bu durum, normalden daha yüksek kan şekeri seviyelerine yol açar. Gestasyonel diyabet genellikle gebelik sonrasında kendiliğinden düzelir, ancak hem anne hem de çocuk için sağlık risklerini artırabilir. Gestasyonel diyabet olan kadınlar, doğum sonrası diyabet riski altında olabilirler ve düzenli takip gerektirebilirler.

Sonuç:

Her tür şeker hastalığı, uygun tedavi ve yaşam tarzı değişiklikleriylekontrol altına alınabilir. Diyabetin erken teşhisi ve sürekli takibi önemlidir. Sağlıklı bir beslenme planı, düzenli egzersiz, ilaç tedavisi ve insülin enjeksiyonları, şeker hastalarının sağlıklı bir yaşam sürdürebilmelerine yardımcı olabilir. Ayrıca, diyabet riskini azaltmak için obeziteyle mücadele etmek, sağlıklı kiloyu korumak ve stresi yönetmek gibi önlemler almak da önemlidir.

What are current transformers and what do they do?

Current transformers, often abbreviated as CTs, are vital components in electrical systems designed to measure and monitor electric current. They play a crucial role in ensuring the safety and efficiency of power distribution.

One of the main functions of current transformers is to step down high currents to levels that can be safely measured by instruments and protective devices. By reducing the current to a manageable level, CTs allow for accurate measurements and facilitate the operation of protective devices, such as circuit breakers.

In addition to measurement and protection, current transformers also serve as isolation devices. They create a galvanic separation between the high-voltage primary circuit and the low-voltage secondary circuit, providing a safe means of monitoring current without exposing instruments or personnel to high voltages.

Current transformers come in various types and designs, including wound primary, bar-type, and bushing-mounted CTs. Each type is suitable for specific applications, depending on factors such as the current rating, voltage level, and physical constraints of the electrical system.

Overall, current transformers are indispensable in electrical systems, enabling accurate current measurement, protection, and isolation. Their proper selection, installation, and maintenance are essential for ensuring the reliable and efficient operation of power distribution systems.

Definition and Purpose of Current Transformers

1. Measure and Transform Current

CTs accurately scale down high currents to a level that can be safely handled by measuring instruments.

2. Protect Equipment

They safeguard equipment from damage by detecting and responding to abnormal currents and short circuits.

3. Precise Monitoring

Current transformers enable accurate monitoring and control of current flow in electrical systems.

Basic Principle

CTs work on the principle of magnetic induction to measure electric current. When an electric current flows through a conductor, it generates a magnetic field around it. This magnetic field can be harnessed by a current transformer to accurately measure the current passing through the conductor. The core of a current transformer is made of a highly permeable material, such as iron or ferrite, which enhances the magnetic properties. The primary winding is connected in series with the conductor carrying the current to be measured. As the current flows through the primary winding, it creates a magnetic field in the core. According to Faraday’s law of electromagnetic induction, any change in the magnetic field through a coil will induce a voltage across the coil. In the case of a current transformer, the secondary winding is wound around the core, and the induced voltage in the secondary winding is proportional to the primary current. This induced voltage in the secondary winding can then be measured and scaled down to represent the actual current passing through the primary conductor. By carefully selecting the turns ratio between the primary and secondary windings, current transformers can accurately step down the primary current to a lower, more manageable level for measurement purposes. Overall, current transformers provide a reliable and non-intrusive method of measuring electric current. Their use in various applications, from power distribution to industrial processes, helps ensure the safety, efficiency, and proper functioning of electrical systems.

Secondary Current

The primary current induces a secondary current in the CT’s winding, which is proportional to the primary current. This principle of electromagnetic induction forms the foundation of how current transformers (CTs) operate. CTs are vital components in electrical systems, designed to accurately measure and monitor electric current. When an electric current flows through the primary winding of a CT, it creates a magnetic field around the core. This magnetic field, in turn, induces a secondary current in the secondary winding of the CT. The secondary current is proportional to the primary current, allowing for accurate measurement and monitoring of the electrical current. By stepping down the primary current to a lower, more manageable level, CTs enable the use of instruments and protective devices that are designed to operate within specific current ranges. This ensures the safety and efficiency of power distribution systems by preventing overloads and facilitating proper circuit protection. CTs are available in various types and designs, including wound primary, bar-type, and bushing-mounted CTs. Each type has its own advantages and is suitable for specific applications based on factors like current rating, voltage level, and physical constraints of the electrical system. In summary, current transformers play a critical role in accurately measuring and monitoring electric currents in electrical systems. By utilizing the principle of electromagnetic induction, CTs enable safe and efficient operation of power distribution systems, contributing to the overall reliability and performance of electrical installations.

Types of Current Transformers

  1. Split-Core
    • Allows for easy installation without disconnecting the primary conductor.
  2. Wound
    • Features a circular magnetic core with a primary winding and a secondary winding.
  3. Toroidal
    • Consists of a donut-shaped core with the primary conductor passing through the center.

Applications of Current Transformers

  1. 5K -Industrial Systems
  2. 2K+ Power Plants

Advantages of Using Current Transformers

Accurate Monitoring : Enables precise measurement and control of current flow.

Equipment Protection: Ensures the safety and reliability of electrical devices and machinery.

Common Challenges and Limitations of Current Transformers

Accuracy Issues: May experience accuracy limitations based on load and environmental conditions.

Saturation: Can saturate under fault conditions, affecting accuracy and performance.

Temperature Effects: Performance may be impacted by extreme temperatures.

Conclusion and Key Takeaways

Essential Component

CTs are indispensable in ensuring safe and reliable electrical operations.

Continuous Advancements

Ongoing developments are enhancing the accuracy and efficiency of current transformers.

Flutter ile Bluetooth Cihazları Tarama ve Bağlantı Kurup/Kaldırma Uygulaması – 3 (Izınler ve Kontroller)

Flutter ile Bluetooth Cihazları Tarama ve Bağlantı Kurup/Kaldırma Uygulaması – 1 başlığı altında verilen kodda, import kısmında flutter_blue kutuphanesine prefix verilerek tanımlanmasının sebebi flutter_reactive_ble kutuphanesinin de BluetoothDevice sınıfına sahip olmasıdır. Hangi kutuphanenin BluetoothDevice sınıfını kullanacağımızı belirtmek için kütüphanelerin birine prefix vermemiz gerekti.

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_blue/flutter_blue.dart' as flutter_blue;
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:open_settings/open_settings.dart';
import 'package:permission_handler/permission_handler.dart';

flutter_blue kutuphanesine ait bir sınıf, metod veya özellik kullanıldığı zaman artık bunu belirtmemiz gerekmektedir. flutter_blue.FlutterBlue.instance veya flutter_blue.BluetoothDevice gibi kullanımlarının sebebi budur.

Uygulamanın amacı çevredeki bağlanabilecek cihazları taramak ve bu cihazlara bağlanıp, bağlı cihazlarla da bağlantıyı koparmak olduğundan iki tane boş liste tanımladık.

Bulunan cihazları listelemek için:

List<DiscoveredDevice> _discoveredDeviceList = [];

Bağlı olduğumuz cihazları listelemek için:

List<DiscoveredDevice> _connectedBluetoothDeviceList = [];

Konum ve bluetooth izinlerini uygulama başlatıldığında almak için _getBluetoothPermission(), _getLocationPermission(), _getPermissions() methodları initState içerisinde çağrıldılar.

@override
void initState() {
super.initState();

// setting devices orientation on landscape
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
]);

_getBluetoothPermission();
_getLocationPermission();
_getPermissions();
}

Uygulamaya ilk defa giriş yapıldığında konum ve bluetooth izinleri verilmemiş olacağından if bloğuna ilk olarak bluetoothPermission.isDenied ve locationPermission.isDenied koşullarıyla başladık böylece izin verildikten sonra bu koşullar false döndüreceğinden if bloğu tekrar koşmayacaktır.

İzinler verildikten sonra if bloğu bluetoothPermission.isDenied koşulunu sağlamayıp false’a düştüğü için sonraki koşmalarda else bloğu içerisindeki print komutu koşacak ve konsola Not Granted yazılacak, bu print komutunu Granted olarak değiştirmeniz daha doğru olur.

Future<bool> _getBluetoothPermission() async {
var bluetoothPermission = await Permission.bluetoothScan.status;

if (bluetoothPermission.isDenied) {
if (await Permission.bluetoothScan.request().isGranted) {
if (await Permission.bluetoothConnect.request().isGranted) {
print("Blueooth Permission: Granted");
return true; // Permission granted
}
}
} else {
print("Blueooth Permission: Granted");
}
return false;
}

Future<bool> _getLocationPermission() async {
var locationPermission = await Permission.location.status;

if (locationPermission.isDenied) {
if (await Permission.location.request().isGranted) {
if (await Permission.accessMediaLocation.request().isGranted) {
print("Location Permission: Granted");
return true; // Permission granted
}
}
} else {
print("Location Permission: Granted");
}
return false;
}

Alttaki _getPermissions metodunun tanımlanmasının sebebi ise yukarıdaki gibi izinleri teker teker çağırmak yerine tüm izinleri tek seferde çağırmayı denemek içindir. if bloğu içerisindeki koşulda tüm izinler izin verilmediği sürece true döndürmesi istenmiştir ama şuanki durumda izinlerden sadece birine bile izin verildiği taktirde await Permission.location.status.isDenied && await Permission.bluetoothScan.status.isDenied ifadesi false döndürür.

Bunun için && (AND) ifadesi yerine || (OR) ifadesi kullanmamız gerekmektedir veya her iki ifadenin de başına ! işareti koyabilirsiniz. Böylece sadece tüm izinler verildiği takdirde koşulumuz false döndürür ve if bloğu koşmaz.

Future<void> _getPermissions() async {
// Requesting multiple permissions at once.
if (!await Permission.location.status.isDenied &&
!await Permission.bluetoothScan.status.isDenied) {
Map<Permission, PermissionStatus> statuses = await [
Permission.location,
Permission.bluetoothScan,
].request();
print(statuses[Permission.location]);
print(“\n”);
print(statuses[Permission.bluetoothScan]);
}
}

Çevredeki cihazları taramamız için gereken şartlar sadece izinler değil, aynı zamanda taramaya çalıştığımız zamanda hem bluetooth hem de konum özelliklerinin o anda açık olması gerekmektedir. Bunu kontrol etmek için de _chechkIfBluetoothIsOn ve _chechkIfLocationIsOn methodlarını tanımladık.

Future<bool> _chechkIfBluetoothIsOn() async {
// Check bluetooth service status
var isBluetoothOn = await Permission.bluetooth.serviceStatus.isEnabled;

if (!isBluetoothOn) {
// propmpt user to enable the bluetooth if the bluetooth is off
showDialog(
context: context,
builder: (_) => AlertDialog(
title:
Text("Bluetooth Özelliği ${isBluetoothOn ? "Açık" : "Kapalı"}"),
content: const Text(
"Bu özelliği kullanmak için bluetooth özelliğinin açık olması gerekir."),
actions: [
ElevatedButton(
onPressed: () =>
Navigator.of(context, rootNavigator: true).pop(false),
child: Text(isBluetoothOn ? "Kapat" : "Vazgeç")),
ElevatedButton(
// make the button not intractable when the location is on
onPressed: () async => isBluetoothOn
? null
: {
Navigator.of(context, rootNavigator: true).pop(),
await OpenSettings.openBluetoothSetting(),
},
child: Text(isBluetoothOn ? "" : "Aç")),
],
elevation: 12.0,
backgroundColor: Colors.white,
),
barrierDismissible: true,
);
} else {
//dismiss dialog box
}
return isBluetoothOn;
}

Burada bluetooth servisi açık değilse kullanıcıyı AlertDialog ile uyarıyoruz ve bluetooth servisini açması için yönlendiriyoruz.

await OpenSettings.openBluetoothSetting() satırının amacı Aç tuşuna tıklandığında kullanıcıyı bluetooth ayarlarına yönlendirmek, bu methodu ‘open_settings‘ kutuphanesini import ederek kullanabiliyoruz.


Navigator.of(context, rootNavigator: true).pop(), satırı ise kullanıcıyı yönlendirdiğimizde AlertDialog’u kapatmak içindir, böylece kullanıcı izin verip uygulamaya döndüğünde AlertBox ile karşılaşmayacak.

İlk başlıkta verilen kodda Scan Devices ve List Connected Devices tuşlarında hem if koşulunda hem de ek olarak onPressed metodu altında bluetooth ve konum izinleri istendiğinden iki tane AlertDialog üst üste oluşturulmaktadır. Bu durumu çözmek için _chechkIfBluetoothIsOn ve _checkIfLocationIsOn satırları “Scan Devices” ve “List Connected Devices” tuşlarının onPressed metodundan silinebilir.

TextButton(
onPressed: () async {
_getPermissions();
/* _chechkIfBluetoothIsOn();
_checkIfLocationIsOn(); */

if (await _chechkIfBluetoothIsOn() &&
await _checkIfLocationIsOn()) {
_scanForAvaileableBluetoothDevices();
} else {
print(
"Blueooth veya Location özellikleri açık olmadığından tarama yapılamadı.");
}
},
child: const Text('Scan Devices'),

Yukarıda gösterildiği gibi bu iki satırı yorum satırı da yapabilirsiniz, aynı durum “List Connected Devices” tuşu için de geçerlidir ve aynı işlemi o tuş için de uygulayabilirsiniz.

Flutter ile Bluetooth Cihazları Tarama ve Bağlantı Kurup/Kaldırma Uygulaması – 2

Flutter reactive BLE ve FlutterBlue kütüphaneleri bluetooth cihazlarını bulmak, bağlanmak ve bu cihazlar üzerinden bilgi çekmek için kullanılanılan kütüphanelerdir.

Bu uygulamada Flutter reactive Ble kütüphanesini çevredeki bluetooth cihazlarını bulmak, listelemek ve bağlanmak için, FlutterBlue kütüphanesini de bağlı olduğumuz cihazları listelemek için kullanıyoruz.

Kodların işlevlerini açıklamadan önce kısaca bluetooth cihazlarının çalışma mantığına göz atalım. Uygulamalarımız bluetooth donanımlarıyla iletişim kurarken alttaki katmanlı yapıda Generic Access Profile (GAP) ve Generic Attribute Profile (GATT) katmanları üzerinden bluetooth cihaza bağlanma ve bağlandıktan sonraki iletişim için bu katmanları kullanırlar.

GAP: Cihazların keşfedilmesi ve birbirleri arasındaki bağlantı ile ilgili prosedürlerin çoğunu GAP katmanı üstlenir.

GATT: Uygulamalarımız, GATT katmanını bağlı olan iki cihaz arasındaki veri iletimini sağlamak için kullanır.

GATT iki cihaz arasında bağlantı sağlandıktan sonra devreye girer yani ilk önce GAP ile cihazlar birbirine bağlanıyor sonra GATT ile birbirleri arasında veri alışverişini gerçekleştiriyorlar.

ATT (Attribute Proctocol): Service ve Characteristic ve ilişkili verilerin, herbiri benzersiz 16-bitlik ID’lerle basit tablolar şeklinde tutulması için kullanılır.

GATT server: GATT Client tarafından yazılan veya okunan “characterictic veritabanını” bulunduran cihazlardır.

GATT client: GATT server’dan verileri okuyan veya server’a yazan cihazlardır.

Peripheral: bağlanacağımız bluetooth cihazlar (saat, kulaklık, fare, klavye, sensörler gibi)

Center: bağlantıyı yapacak olduğumuz cihazlar (telefon, tablet, bilgisayar gibi)

Bu durumda her iki cihazda GATT server ve GATT client olabilir, her iki cihazda birbiri üzerinde okuma ve yazma işlemi gerçekleştiriyor.

Peripheral ile center arasındaki ilişki tekli şekildedir yani peripheral bir center ile bağlantı halindeyken, diğer cihazlar bu peripheral’ı göremezler veya bu peripheral’a bağlanamazlar. Bu durum peripheral ve center arasındaki bağlantı sonlanıncaya kadar böyle devam eder.

Center ile peripheral arasındaki ilişki ise çoklu olabilir yani bir center birden fazla peripheral ile aynı anda bağlı olabilir.

Profile: Service kümesi, (Fitness profili; kalp atış hızı servisi, kan basıncı servisi gibi servisleri içerir)

Service: Characteristic kümesi, (Kalp atış hızı servisi; kalp atış hızı değeri, kalp atış hızlarının zamanı gibi karakteristikleri içerir)

Characteristic: Değer ve Başlıktan (Value ve Label) oluşan veri (kalp atış hızı değeri: 10 gibi)

Profile: Neyin sunulduğunu,

Service: Nasıl sunulduğunu,

Characteristic ise Ne sunulduğunu tanımlar.

Veriler cihazların belleğinde “characteristic” şeklinde tutulurlar.

Peripheralların birbiri arasında veri alışverişi yapmaları gerektiği durumlarda bu işlem center üzerinden gerçekleştirilir.

Bizim yaptığımız uygulamanın çalışma şeklini ve yaptığımız listelemeler ve listeler arasındaki ilişkilerin anlam kazanması için buraya kadar olan kısım yeterlidir.

Daha fazla bilgiye sahip olmak isterseniz alttaki linklere göz atabilirsiniz:
https://www.bluetooth.com/bluetooth-resources/bluetooth-5-go-faster-go-further/

https://docs.silabs.com/bluetooth/6.1.0/bluetooth-gatt

https://learn.adafruit.com/introduction-to-bluetooth-low-energy/gatt

https://software-dl.ti.com/lprf/simplelink_cc2640r2_latest/docs/blestack/ble_user_guide/html/ble-stack-3.x/gatt.html

Flutter ile Bluetooth Cihazları Tarama ve Bağlantı Kurup/Kaldırma Uygulaması – 1

Uygulamada hem taranan cihazlar listeleneceği hem de telefonumuzun bağlantıda olduğu cihazların listeleneceği bir arayüz kullanılacak. Iki liste yan yana sergileneceği için uygulamanın yönü landscapeRight ve landscapeLeft olarak ayarlanmıştır.

Ekranı yan döndürme işlemi alttaki kod bloğu ile gerçekleştirebilir.

@override
void initState() {
super.initState();

// setting devices orientation on landscape
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
]);
}

Aynı zamanda DeviceOrientation.portraitDown ve DeviceOrientation.portraitUp satırları ile de uygulamanın sadece dikey eksenlerde çalışması sağlanabilir.

Uygulamanın şu anki görüntüsü aşağıdaki gibidir.

Uygulamamızın çalışma mantığı alttaki akış şemasında verilmiştir.

Çevredeki bağlanılabilecek cihazları bulup listelemek için Appbar’da yer alan “Scan Devices” TextButton’a tıklıyoruz. “List Connected Devices” TextButton’a tıklandığında ise bize o anlık bağlı olunan cihazlar listelenecek.

Ekranın sol kısmında bağlanmaya hazır cihazlar, sağ kısmında ise bağlı olduğumuz cihazlar listelenmektedir. Soldaki listeden seçilen bir cihaza bağlanılması durumunda listeler güncellenecektir, yani seçtiğimiz cihaza başarılı bir şekilde bağlanabilirsek artık cihaz sağda listelenecektir. Ayni mantikla sağ listede yer alan bir cihaz ile olan bağlantının kalkması durumunda bu cihaz da listeler güncellendiğinde sol listede yer alacaktır.

Uygulamanın kodu altta verilmiştir, main.dart dosyası:

import 'dart:async';
import 'dart:core';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_blue/flutter_blue.dart' as flutter_blue;
import 'package:flutter_blue/gen/flutterblue.pb.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:open_settings/open_settings.dart';
import 'package:permission_handler/permission_handler.dart';

void main() {
runApp(const MaterialApp(
debugShowCheckedModeBanner: false,
home: MyApp(),
));
}

class MyApp extends StatelessWidget {
const MyApp({super.key});

// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Android Studio',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}

class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});

final String title;

@override
State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
final _reactive_Ble = FlutterReactiveBle();
final _flutter_Blue = flutter_blue.FlutterBlue.instance;
// Discovered Device List
List<DiscoveredDevice> _discoveredDeviceList = [];
// To get Device Connection States
Stream<ConnectionStateUpdate> get state => _deviceConnectionController.stream;
// Connection Update Control Stream
final _deviceConnectionController = StreamController<ConnectionStateUpdate>();
//Bluetooth Low Energy Connection State Update
late StreamSubscription<ConnectionStateUpdate> _ble_Connection;
String connectionMessage = "";
// Connected Bluetooth Device List
List<flutter_blue.BluetoothDevice> _connectedBluetoothDeviceList = [];

// defined to be used for defining UI behavior
var _isConnecting = false;

@override
void initState() {
super.initState();

// setting devices orientation on landscape
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
]);

_getBluetoothPermission();
_getLocationPermission();
_getPermissions();
}

// Listen to stateStream for updates
/*FlutterBlue.instance.state.listen((BluetoothState state) {});*/

Future<bool> _getBluetoothPermission() async {
var bluetoothPermission = await Permission.bluetoothScan.status;

if (bluetoothPermission.isDenied) {
if (await Permission.bluetoothScan.request().isGranted) {
if (await Permission.bluetoothConnect.request().isGranted) {
print("Blueooth Permission: Granted");
return true; // Permission granted
}
}
} else {
print("Blueooth Permission: Not Granted");
}
return false;
}

Future<bool> _getLocationPermission() async {
var locationPermission = await Permission.location.status;

if (locationPermission.isDenied) {
if (await Permission.location.request().isGranted) {
if (await Permission.accessMediaLocation.request().isGranted) {
print("Location Permission: Granted");
return true; // Permission granted
}
}
} else {
print("Location Permission: Not Granted");
}
return false;
}

Future<void> _getPermissions() async {
// Requesting multiple permissions at once.
if (await Permission.location.status.isDenied &&
await Permission.bluetoothScan.status.isDenied) {
Map<Permission, PermissionStatus> statuses = await [
Permission.location,
Permission.bluetoothScan,
].request();
print(statuses[Permission.location]);
print("\n");
print(statuses[Permission.bluetoothScan]);
}
}

Future<bool> _chechkIfBluetoothIsOn() async {
// Check bluetooth service status
var isBluetoothOn = await Permission.bluetooth.serviceStatus.isEnabled;

if (!isBluetoothOn) {
// propmpt user to enable the bluetooth if the bluetooth is off
showDialog(
context: context,
builder: (_) => AlertDialog(
title:
Text("Bluetooth Özelliği ${isBluetoothOn ? "Açık" : "Kapalı"}"),
content: const Text(
"Bu özelliği kullanmak için bluetooth özelliğinin açık olması gerekir."),
actions: [
ElevatedButton(
onPressed: () =>
Navigator.of(context, rootNavigator: true).pop(false),
child: Text(isBluetoothOn ? "Kapat" : "Vazgeç")),
ElevatedButton(
// make the button not intractable when the location is on
onPressed: () async => isBluetoothOn
? null
: {
Navigator.of(context, rootNavigator: true).pop(),
await OpenSettings.openBluetoothSetting(),
},
child: Text(isBluetoothOn ? "" : "Aç")),
],
elevation: 12.0,
backgroundColor: Colors.white,
),
barrierDismissible: true,
);
} else {
//dismiss dialog box
}
return isBluetoothOn;
}

Future<bool> _checkIfLocationIsOn() async {
// Check location service status
var isLocationOn =
await Permission.locationWhenInUse.serviceStatus.isEnabled;

if (!isLocationOn) {
// Request location permission
showDialog(
context: context,
builder: (_) => AlertDialog(
title: Text("Konum Özelliği ${isLocationOn ? "Açık" : "Kapalı"}"),
content: const Text(
"Bu özelliği kullanmak için konum özelliğinin açık olması gerekir."),
actions: [
ElevatedButton(
onPressed: () =>
Navigator.of(context, rootNavigator: true).pop(false),
child: Text(isLocationOn ? "Kapat" : "Vazgeç")),
ElevatedButton(
// make the button not intractable when th location is on
onPressed: () async => isLocationOn
? null
: {
Navigator.of(context, rootNavigator: true).pop(),
await OpenSettings.openLocationSourceSetting(),
},
child: Text(isLocationOn ? "" : "Aç")),
],
elevation: 12.0,
backgroundColor: Colors.white,
),
barrierDismissible: true,
);
} else {}
return isLocationOn;
}

void _scanForAvaileableBluetoothDevices() {
setState(() {
_discoveredDeviceList = [];
});

StreamSubscription<DiscoveredDevice> scanSubscription =
_reactive_Ble.scanForDevices(
withServices: [],
scanMode: ScanMode.lowLatency,
).listen((device) {
setState(() {
// if device has a name and not on the list, add device to the list
if (!_discoveredDeviceList
.any((element) => element.id == device.id) &&
device.name != "") {
_discoveredDeviceList.add(device);
}
});
}, onError: (error) {
print("Error occured while scanning: $error");
});

Future.delayed(const Duration(seconds: 10)).then((_) {
scanSubscription.cancel();
print("Scan completed");
});

print("Available Bluetooth Devices is Dsplayed:");
}

Future<void> _listConnectedBluetoothDevices() async {
var connectedDevices = await _flutter_Blue.connectedDevices;

setState(() => _connectedBluetoothDeviceList = connectedDevices );
print("_connectedBluetoothDeviceList.lenght: ${_connectedBluetoothDeviceList.length}");
print("connectedDevices count: ${connectedDevices.length}");
print("Connected Device List is Displayed:");
}

Future<void> _connectToTheSelectedDevice(
BuildContext context,
DiscoveredDevice discoveredDevice
) async {

setState(() {
_isConnecting = true;
});

_ble_Connection = _reactive_Ble.connectToDevice(
id: discoveredDevice.id,
connectionTimeout: const Duration (seconds: 30)).listen((update) async {
// connection update handler (async)
print('ConnectionState for device : ${update.connectionState}');

setState(() {
if (update.connectionState == DeviceConnectionState.connecting) {
connectionMessage = "Connecting...";
}

if (update.connectionState == DeviceConnectionState.connected) {
connectionMessage =
"Connected";
}

if (update.connectionState == DeviceConnectionState.disconnected) {
connectionMessage = "Disconnected";
}
});
_deviceConnectionController.add(update);

if (update.connectionState == DeviceConnectionState.connecting) {}
if (update.connectionState == DeviceConnectionState.connected) {
_isConnecting = false;
print("Recalling the updated lists after connecting a device");
_scanForAvaileableBluetoothDevices();
_listConnectedBluetoothDevices();
}
if (update.connectionState == DeviceConnectionState.disconnected) {
_isConnecting = false;
print("DeviceConnectionState.disconnected");
print("Recalling the updated lists after disconnecting a device");
_scanForAvaileableBluetoothDevices();
_listConnectedBluetoothDevices();
}
},
onError: (Object error) => print("Connecting to device resulted in error $error"),
);
}

@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xfff5f5f5),
appBar: AppBar(
elevation: 0,
centerTitle: false,
automaticallyImplyLeading: false,
backgroundColor: const Color(0xffffffff),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.zero,
),
title: const Text(
"AppBar",
style: TextStyle(
fontWeight: FontWeight.w400,
fontStyle: FontStyle.normal,
fontSize: 14,
color: Color(0xff000000),
),
),
actions: [
TextButton(
onPressed: () async {
_getPermissions();
_chechkIfBluetoothIsOn();
_checkIfLocationIsOn();

if (await _chechkIfBluetoothIsOn() &&
await _checkIfLocationIsOn()) {
_scanForAvaileableBluetoothDevices();
} else {
print(
"Blueooth ve Location özellikleri açık olmadığından tarama yapılamadı.");
}
},
child: const Text('Scan Devices'),
),
TextButton(
onPressed: () async {
_getPermissions();
_chechkIfBluetoothIsOn();
_checkIfLocationIsOn();

print("Connected Device Count: ${_connectedBluetoothDeviceList.length}");

if (await _chechkIfBluetoothIsOn() &&
await _checkIfLocationIsOn()) {
_listConnectedBluetoothDevices();
} else {
print(
"Blueooth ve Location özellikleri açık olmadığından liste yenilenemedi.");
}
},
child: const Text('List Connected Devices'),
)
],
),
body: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: ListView.builder(
itemCount: _discoveredDeviceList.length,
itemBuilder: (BuildContext context, int index) {
final scanned_Device = _discoveredDeviceList[index];
return Column(
children: [
ListTile(
title: Text(scanned_Device.name),
subtitle: Text(scanned_Device.id),
trailing: ElevatedButton(
onPressed: _isConnecting
? null
: () {
_connectToTheSelectedDevice(context, scanned_Device);
print(_connectedBluetoothDeviceList.length);
},
child: const Text("Bağlan"),
style: ElevatedButton.styleFrom(
backgroundColor: _isConnecting
? Colors.red
: Colors.green,
foregroundColor: Colors.white,
),
),
tileColor: Colors.lightBlue,
textColor: Colors.white,
),
],
);
},
),
),
Expanded(
child: ListView.builder(
itemCount: _connectedBluetoothDeviceList.length,
itemBuilder: (BuildContext context, int index) {
final connected_Device = _connectedBluetoothDeviceList[index];
return Column(
children: [
ListTile(
title: Text(connected_Device.name),
subtitle: Text("${connected_Device.id}"),
trailing: ElevatedButton (
onPressed: () async {
_ble_Connection.cancel();
//connected_Device.disconnect();
print("connected_Device.disconnect() Ran");
await Future.delayed(const Duration(milliseconds: 100));
_listConnectedBluetoothDevices();
print("_listConnectedBluetoothDevices() Ran");
},
child: const Text("Unut"),
),
),
],
);
},
),
)
],
),
);
}

@override
void dispose() {
super.dispose();
}
}

pubspec.yaml dosyası:

name: ...
description: "..."

publish_to: 'none' # Remove this line if you wish to publish to pub.dev

version: 1.0.0+1

environment:
sdk: '>=3.3.0 <4.0.0'

dependencies:
flutter:
sdk: flutter

open_settings:

cupertino_icons: ^1.0.6
flutter_svg: ^2.0.10+1
flutter_reactive_ble: ^5.3.1
permission_handler: ^11.2.0
flutter_joystick: ^0.0.4
flutter_blue: ^0.8.0
get:

dev_dependencies:
flutter_test:
sdk: flutter

flutter_lints: ^3.0.0

flutter:

uses-material-design: true

android/app/src/main/AndroidManifest.xml dosyasında <manifest> ve <application> başlıkları arasına altta verilen şekilde <usus-permission …> satırlarını ekleyin:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
tools:remove="android:usesPermissionFlags"/>

<application ...>

android/app/src/build.gradle dosyasında android { … defaultConfig { … bloğunun içinde minSdkVersion’u 21 olarak değiştirin:

android {
namespace "com.beyhude.flutterandroidstudio"
compileSdk flutter.compileSdkVersion
ndkVersion flutter.ndkVersion

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.beyhude.flutterandroidstudio"
// 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 21
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}

Bir sonraki yazıda Bluetooth cihazlarının çalışma mantığına, kod anlatımlarına ve rastlanılan hatalara değinilecektir, eğer yukarıdaki kodlar direkt olarak çalışmazsa:
https://pub.dev/packages/flutter_blue,
https://pub.dev/packages/flutter_reactive_ble,
https://pub.dev/packages/permission_handler/install ve
https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration
sayfalarından yararlanabilirsiniz. İyi günler.