Related
I am using this library https://pub.dev/packages/flutter_reactive_ble for scanning the beacon. and for broadcasting a beacon I am using an android app called beacon simulator and it has got beacon UUID, majorID and minorID for each hosted beacon.
here the UUID is '0546b93b-f113-438d-8bab-b9e766dd'
but while scanning I am unable to look out for UUID instead I am getting this response in this structure.
DiscoveredDevice(id: 14:49:2F:BB:D5:97, name: , serviceData: {}, serviceUuids: [], manufacturerData: [76, 0, 2, 21, 5, 70, 185, 59, 241, 19, 67, 141, 139, 171, 185, 231, 102, 208, 17, 119, 0, 0, 0, 0, 191], rssi: -39)
Is there any way I can get the beacon's UUID in the format '0546b93b-f113-438d-8ba...'
Or any better way to uniquely identify a device? I know we can search for the device's Bluetooth address, but that just keeps on changing.
Thanks in advance.
Is there any Flutter package available that can listen for Eddystone UID beacons and Eddystone-URLs?
I have been looking at various packages such as beacons_plugin and flutter_beacon but I cannot seem to find any package that can receive these beacon broadcasts.
Has anyone been able to achieve this? If so, how?
Thank's #ukBaz - I am now seeing the Eddystone data. However i am trying to get the namespace id and instance data from the device.
I am using a Minew D15N BLE beacon and printing out the data..
I/flutter (27645): device id: AC:23:3F:6A:FE:85, name: , type: BluetoothDeviceType.le found! rssi: -68
I/flutter (27645): advertisementData => localName: , txPowerLevel: null, connectable: false
I/flutter (27645): advertisementData -> serviceUuids length: 1
I/flutter (27645): 0000feaa-0000-1000-8000-00805f9b34fb
I/flutter (27645): advertisementData -> manufacturerData length: 0
I/flutter (27645): advertisementData -> serviceData length: 1
I/flutter (27645): 0000feaa-0000-1000-8000-00805f9b34fb: [0, 232, 113, 28, 115, 246, 74, 253, 206, 7, 183, 227, 153, 153, 153, 153, 153, 153]
I sometimes also receive this..
advertisementData -> manufacturerData length: 1
I/flutter (27645): 76: [2, 21, 144, 156, 60, 249, 252, 92, 72, 65, 182, 149, 56, 9, 88, 165, 26, 90, 234, 95, 39, 15, 204]
Based on this documentation (not sure if this is right) I was trying this..
var naaa = ByteData.sublistView(manufacturerData, 2, 11);
But get this following error..
Uncaught Error: TypeError: null: type 'JSNull' is not a subtype of type 'List<int>'
Here is a screen shot of the UID slot that i have setup to test..
Those packages look like they are just for iBeacon which uses manufacturer data in the advertising packet. For Eddystone it uses service data. The flutter_blue library give you access to the service data. https://pub.dev/documentation/flutter_blue/latest/flutter_blue/AdvertisementData-class.html
The following answer shows how to scan and access the advertising data with flutter_blue: https://stackoverflow.com/a/63591662/7721752
I've encountered a problem deploying Django Channels on Heroku, whilst using a RedisChannelLayer.
I get a UnicodeError: encoding with 'idna' codec failed (UnicodeError: label empty or too long) during connection (full traceback below).
That seems to be a problem related to one of the labels in the host address being too long as shown in this python issue.
I printed some information out of my consumer, and also wrapped python's socket.getaddrinfo module to display host and connection information.
This related post has has the same problem connecting to shopify, not a redis instance, where they got around it by placing credentials into the request header. But I don't have control over channels_redis or asyncio.
Any clues?
Properties of the Django Channels Consumer:
.groups []
.channel_layer RedisChannelLayer(hosts=[{'address': ('h:alongkeycomprisingof65charsintotalxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx#ec2-18-202-152-61.eu-west-1.compute.amazonaws.com', '9759')}])
.channel_name specific.OSfTzyqY!pdvgHnaCxWiv
.room_name 8e3d3083-8bb1-4d85-89d3-4496d9b9e946
.room_group_name twined_8e3d3083-8bb1-4d85-89d3-4496d9b9e946
Full Traceback:
Traceback (most recent call last):
File "/app/.heroku/python/lib/python3.6/site-packages/channels/sessions.py", line 183, in __call__
return await self.inner(receive, self.send)
File "/app/.heroku/python/lib/python3.6/site-packages/channels/middleware.py", line 41, in coroutine_call
await inner_instance(receive, send)
File "/app/.heroku/python/lib/python3.6/site-packages/channels/consumer.py", line 59, in __call__
[receive, self.channel_receive], self.dispatch
File "/app/.heroku/python/lib/python3.6/site-packages/channels/utils.py", line 51, in await_many_dispatch
await dispatch(result)
File "/app/.heroku/python/lib/python3.6/site-packages/channels/consumer.py", line 73, in dispatch
await handler(message)
File "/app/.heroku/python/lib/python3.6/site-packages/channels/generic/websocket.py", line 175, in websocket_connect
await self.connect()
File "/app/backend/pink/consumers.py", line 24, in connect
await self.channel_layer.group_add(self.room_group_name, self.channel_name)
File "/app/.heroku/python/lib/python3.6/site-packages/channels_redis/core.py", line 589, in group_add
async with self.connection(self.consistent_hash(group)) as connection:
File "/app/.heroku/python/lib/python3.6/site-packages/channels_redis/core.py", line 835, in __aenter__
self.conn = await self.pool.pop()
File "/app/.heroku/python/lib/python3.6/site-packages/channels_redis/core.py", line 73, in pop
conns.append(await aioredis.create_redis(**self.host, loop=loop))
File "/app/.heroku/python/lib/python3.6/site-packages/aioredis/commands/__init__.py", line 175, in create_redis
loop=loop)
File "/app/.heroku/python/lib/python3.6/site-packages/aioredis/connection.py", line 113, in create_connection
timeout)
File "/app/.heroku/python/lib/python3.6/asyncio/tasks.py", line 339, in wait_for
return (yield from fut)
File "/app/.heroku/python/lib/python3.6/site-packages/aioredis/stream.py", line 24, in open_connection
lambda: protocol, host, port, **kwds)
File "/app/.heroku/python/lib/python3.6/asyncio/base_events.py", line 750, in create_connection
infos = f1.result()
File "/app/.heroku/python/lib/python3.6/concurrent/futures/thread.py", line 56, in run
result = self.fn(*self.args, **self.kwargs)
File "./backend/amy/asgi.py", line 69, in mygetaddrinfo
for res in socket._socket.getaddrinfo(host, port, family, type, proto, flags):
UnicodeError: encoding with 'idna' codec failed (UnicodeError: label empty or too long)
I've been able to work around by establishing my RedisChannelLayer using a dict of arguments to create_connection (as mentioned here, instead of providing a really long host name.
By manually parsing the password out of the REDIS_URL variable that heroku provides me, and rebuilding a host uri without it, I can add that password as a separate field to the create_connection dict, keeping the host string length below 64 characters.
I do this in my settings.py file which now looks like:
def parse_redis_url(url):
""" parses a redis url into component parts, stripping password from the host.
Long keys in the url result in parsing errors, since labels within a hostname cannot exceed 64 characters under
idna rules.
In that event, we remove the key/password so that it can be passed separately to the RedisChannelLayer.
Heroku REDIS_URL does not include the DB number, so we allow for a default value of '0'
"""
parsed = urlparse(url)
parts = parsed.netloc.split(':')
host = ':'.join(parts[0:-1])
port = parts[-1]
path = parsed.path.split('/')[1:]
db = int(path[0]) if len(path) >= 1 else 0
user, password = (None, None)
if '#' in host:
creds, host = host.split('#')
user, password = creds.split(':')
host = f'{user}#{host}'
return host, port, user, password, db
REDIS_URL = env('REDIS_URL', default='redis://localhost:6379')
REDIS_HOST, REDIS_PORT, REDIS_USER, REDIS_PASSWORD, REDIS_DB = parse_redis_url(REDIS_URL)
# DJANGO CHANNELS
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [{
'address': f'redis://{REDIS_HOST}:{REDIS_PORT}',
'db': REDIS_DB,
'password': REDIS_PASSWORD,
}],
},
},
}
I'm struggling to understand why I'm getting this error from a part of my program which sends ICMP echo requests on the network. The starnge thing about this is that I can get it to work by letting the socket handle the IP header, but when I set the IP_HDRINCL option and give it a valid IP header, it returns EINVAL error:
initialize
using interface en0 with ip 192.168.1.126 and mac a4:83:e7:43:40:81.
Input start ip/scan range: 192.168.1.1
[45, 0, 0, 1c, 20, 1, 40, 0, 40, 1, 97, 10, c0, a8, 1, 7e, c0, a8, 1, 1, 8, 0, 22, 2a, 97, 3e, 3e, 97]
[69, 0, 0, 28, 32, 1, 64, 0, 64, 1, 151, 16, 192, 168, 1, 126, 192, 168, 1, 1, 8, 0, 34, 42, 151, 62, 62, 151]
Err(Os { code: 22, kind: InvalidInput, message: "Invalid argument" })
To help visualise what's going on, I've put dumps of the data being sent in there when it sends it. the first dump is the data in hex format and the second is just the same but in decimal format.
Here is the code which opens the socket and creates/sends/receives packets:
( Apologies for the probably overwhelming amount of code, just though I should make sure I provide enough info:) )
let response = net_tools::interface::Interface::detect();
if response.is_err() {
panic! {response};
}
let active_interface = response.unwrap();
println!(
"using interface {} with ip {} and mac {}.",
active_interface.get_name(),
active_interface.get_ip_as_struct(),
active_interface.get_mac()
);
let scan_targets = net_tools::TaregtAddresses::retrieve_from_user();
let sock = net_tools::socket_tools::Socket::new_v4().expect("Failed to open socket");
let mut i = 0;
for ipv4addr in scan_targets {
if i == 1 {
break;
}
let mut d = packet_crafter::Packet::new(
active_interface.clone(),
vec![Protocols::IP, Protocols::ICMP],
// vec![Protocols::ICMP],
);
d.ip_header.set_next_protocol(Protocols::ICMP);
d.ip_header.set_dst_ip(Some(ipv4addr.octets()));
// d.ip_header.set_tos(0b11000100);
d.finalize_headers(); // calculates checksums etc
let data = d.build();
println!("{:x?}", data);
println!("{:?}", data);
let response = sock.sendto(data.as_slice(), SocketAddrV4::new(ipv4addr, 21));
println!("{:?}", response);
i += 1;
}
println!("All data sent, receiving response:");
let mut a = [0u8; 56];
let received_data = sock.recv(&mut a);
println!("{:?}", received_data);
let v = a.to_vec();
println!("{:?}", v);
This is how I'm opening a socket, and sending data on it, notice that I call setsockopt and set IP_HDRINCL to 1 when opening it:
pub fn new_v4() -> crate::io::Result<Self> {
unsafe {
let fam = libc::AF_INET; // Set domain family to ipv4
if cfg!(target_os = "linux") {
match cvt(libc::socket(fam, libc::SOCK_RAW | SOCK_CLOEXEC, 1)) {
Ok(fd) => return Ok(Self(Fd::new(fd))),
Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
Err(e) => return Err(e),
}
}
let _fd = cvt(libc::socket(fam, libc::SOCK_RAW, 1))?; // 1 = setting next protocol as ICMP
let _fd = Fd::new(_fd);
_fd.set_cloexec()?;
let socket = Self(_fd);
if cfg!(target_vendor = "apple") {
let payload = &1u32 as *const u32 as *const libc::c_void;
cvt(libc::setsockopt(
*socket.as_inner(),
libc::SOL_SOCKET,
SO_NOSIGPIPE,
payload,
size_of::<libc::c_int>() as libc::socklen_t,
))?;
}
let payload = &1u32 as *const u32 as *const libc::c_void;
cvt(libc::setsockopt(
*socket.as_inner(),
libc::IPPROTO_IP,
libc::IP_HDRINCL,
payload,
size_of::<libc::c_int>() as libc::socklen_t,
))?;
Ok(socket)
}
}
pub fn sendto(&self, buf: &[u8], addr: SocketAddrV4) -> crate::io::Result<usize> {
unsafe {
let (sa, l) = sock_addr_into_raw(addr);
let n = cvt({
libc::sendto(
*self.as_inner(),
buf.as_ptr() as *const libc::c_void,
cmp::min(buf.len(), super::max_len()),
MSG_NOSIGNAL,
&sa as *const _,
l,
)
})?;
Ok(n as usize)
}
}
This is the function to convert the type of the socketAddr:
pub fn sock_addr_into_raw(s: SocketAddrV4) -> (libc::sockaddr, libc::socklen_t) {
unsafe {
let mut storage = mem::MaybeUninit::<libc::sockaddr>::uninit();
let len = mem::size_of::<SocketAddrV4>();
copy_nonoverlapping(
&s as *const _ as *const libc::sockaddr as *const _ as *const u8,
&mut storage as *mut _ as *mut u8,
len,
);
(storage.assume_init(), len as _)
}
}
So back to my point, as you can see from the first segment of code, the IP header in the packet data that I dump is a valid IP header, followed by a valid ICMP header, as far as I'm aware, I have been changing things around to ensure it's valid so correct me if its not. But anyway, I know that all the other parameters being passed into sendto are valid because when I set the IP_HDRINCL socket option to 0 and only send ICMP data then it works...
initialize
using interface en0 with ip 192.168.1.126 and mac a4:83:e7:43:40:81.
Input start ip/scan range: 192.168.1.1
[8, 0, 8a, 92, 3f, 2e, 2e, 3f]
[8, 0, 138, 146, 63, 46, 46, 63]
Ok(8)
All data sent, receiving response:
Ok(28)
[69, 0, 8, 0, 224, 108, 0, 0, 254, 1, 88, 164, 192, 168, 1, 1, 192, 168, 1, 126, 0, 0, 146, 146, 63, 46, 46, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
I've even tried things such as sending an ethernet II header in the packet when IP_HDRINCL is 1, but that still just gives the same OSError. Does anyone know why sending the IP header myself breaks it??
(btw I'm running this on Mac OS Mojave 10.14.6)
New to software development, I'm working through Big Nerd Ranch's book 'Swift Programming'. One of the challenges set by the book is to print an array within a dictionary that contains 15 zip codes and to have them split across three lines in groups of five. The formatting must exactly match how it appears in the book.
I have tried to solve the issue using the information taught in the book with assistance from the developer documentation.
No dice.
This is what I need to print:
Caterham has the following zip codes: [111, 111, 111, 111, 111,
222, 222, 222, 222, 222,
333, 333, 333, 333, 333]
However this is the closest I can get...
var areaCodes = ["Caterham": [111, 111, 111, 111, 111], "Coulsdon": [222, 222, 222, 222, 222], "Purley": [333, 333, 333, 333, 333]]
var caterhamCodes : [Int] = []
for (_, values) in areaCodes {
caterhamCodes += values
}
print("Caterham has the following codes: \(caterhamCodes[0...4]),")
print(" \(caterhamCodes[5...9]),")
print(" \(caterhamCodes[10...14]).")
which prints:
Caterham has the following postcodes: [111, 111, 111, 111, 111],
[222, 222, 222, 222, 222],
[333, 333, 333, 333, 333].
Essentially, I need what I have above minus some square brackets and without the punctuation after each time a block of zip codes is printed. The book specifies that I might need to use a parameter called terminator. It also mentions I might need to learn how to represent special characters in string literals.
I appreciate that this is probably a high level question with a simple answer, but I'm only a few weeks into learning, so I hope I can be forgiven for asking at least a few silly questions!
Welcome to the developer community and have a nice stay!
I am trying to put answer as simple as possible, so here is my attempt:
var areaCodes = ["Caterham": [111, 111, 111, 111, 111],
"Coulsdon": [222, 222, 222, 222, 222],
"Purley": [333, 333, 333, 333, 333]]
let codesArray = areaCodes.values.sorted(by: { $0[0] < $1[0] })
let caterhamString = "Caterham has the following zip codes: ["
var printString = caterhamString
for (index, area) in codesArray.enumerated() {
for code in area {
printString += "\(code), "
}
if index != codesArray.count - 1 {
printString += "\n" + String(repeating: " ", count: caterhamString.count)
}
}
print(printString.dropLast(2).appending("]"))
Hope this helps! Good luck!
Here is a way of getting the desired output :
let intro = "Caterham has the following zip codes: ["
let spaces = ",\n" + String(repeating: " ", count: intro.count)
let areaCodes = ["Caterham": [111, 111, 111, 111, 111], "Coulsdon": [222, 222, 222, 222, 222], "Purley": [333, 333, 333, 333, 333]]
let codes = areaCodes.values.sorted { $0[0] < $1[0] }
var output = intro +
codes.map { $0.map{ String($0) }.joined(separator: ", ") }
.joined(separator: spaces)
+ "]"
print(output)
Which prints
Caterham has the following zip codes: [111, 111, 111, 111, 111,
222, 222, 222, 222, 222,
333, 333, 333, 333, 333]