I'm using zkemkeeper dll in a .net windows forms app.
This is my code
objCZKEM.OnConnected += ObjCZKEM_OnConnected;
objCZKEM.OnDisConnected += objCZKEM_OnDisConnected;
if (objCZKEM.Connect_Net(IPAdd, Port))
{
//65535, 32767
if (objCZKEM.RegEvent(1, 65535))
{
// [ Register your events here ]
// [ Go through the _IZKEMEvents_Event class for a complete list of events
objCZKEM.OnEnrollFinger += ObjCZKEM_OnEnrollFinger;
objCZKEM.OnFinger += ObjCZKEM_OnFinger;
objCZKEM.OnAttTransactionEx += zkemClient_OnAttTransactionEx;
objCZKEM.OnDoor += ObjCZKEM_OnDoor;
}
objCZKEM.RegEvent(1, 65535);
return true;
}
return false;
I can connect to the device get the logs etc.
OnConnected event is fired.
But no real-time event other than OnAttTransactionEx ever gets called. OnFinger and OnDoor don't work. To be honest I haven't registered a new finger so I don't know if OnEnrollFinger works.
I want to block some users from opening the door using some conditions in my own application. I don't know how I can achieve this. I thought I can use OnFinger event and block the user there. But I'm not sure if it is the way to do this.
Thanks in advance
In the latest models' firmware, real time event is disabled due to the business reasons for the cloud solutions from zk. You have to reply on "biometric web api" for getting the real time attendance to your server. If you want to develop only as a desktop application, then you have to poll for the the attendance logs.
For disabling the user from accessing the door, you need to ensure that the user is deleted from the biometric device as soon as you find him/her as ineligible
Related
I have a LaunchPad MK3 Mini MIDI device that I'm looking to tie into a C# app I'm making, where pressing buttons will invoke a various functions within the app. After a bit of research, I landed on using the RtMidi.Core library (thru NuGet). And upon debugging, it appears that I'm able to fully listen to the device and react to events appropriately, and that's good.
I should also back up a bit as well. I'm quite inexperienced to using MIDI devices so a lot of the terminology and industry usage is a bit lost on me. But it's my understanding that a MIDI device can be modified so that the individual keys can be changed to perform a different MIDI event. In my case, I'm not using this for any musical purpose, so there is no need for Note/Piano type events. So I changed all the buttons to be Control Change, all of them with unique Channel/ControlNum combinations. It appears these CC buttons can be one of 3 "Pad Modes":
Momentary - Both KeyDown and KeyUp each will trigger a separate MIDI event
Toggle - Only KeyDown will trigger a MIDI event and each one will alternate between 0 and some specified non-zero value
Trigger - Only KeyDown will trigger a MIDI event, but it will always be the specified non-zero value
Now, as it pertains to my use cases. I'm looking to utilize the 'Trigger' Pad Mode type, as this will trigger some various code which will last a variable duration. My issue is, the MIDI device will change the LED keylight color to its ON color and it NEVER goes back to its initial state (as expected, tbh). So what I'm looking to do is after my 'certain function' is done executing, that it would 'reset' this trigger back to the initial state as its last course of action.
So, I create a ControlChangeMessage with the proper channel/control/value and send it to the MIDI device, but the LED color doesn't seem to change back to the original color. The ONLY thing that seems to reset its state is to unplug the USB power from the device and plug it back in.
For reference: The input and output device names I'm using are similar, but different, as indicated in the code below:
foreach (var inputDeviceInfo in MidiDeviceManager.Default.InputDevices)
{
Console.WriteLine($"Opening {inputDeviceInfo.Name}");
if (inputDeviceInfo.Name == "MIDIIN2 (LPMiniMK3 MIDI) ")
{
var inputDevice = inputDeviceInfo.CreateDevice();
devices.Add(inputDevice);
inputDevice.ControlChange += ControlChangeHandler;
inputDevice.Open();
}
}
foreach (var outputDeviceInfo in MidiDeviceManager.Default.OutputDevices)
{
Console.WriteLine($"Opening {outputDeviceInfo.Name}");
if (outputDeviceInfo.Name == "MIDIOUT2 (LPMiniMK3 MIDI) ")
{
var outputDevice = outputDeviceInfo.CreateDevice();
devicesOut.Add(outputDevice);
outputDevice.Open();
//while (!outputDevice.IsOpen) { }
ControlChangeMessage ccMsg = new ControlChangeMessage(RtMidi.Core.Enums.Channel.Channel3, 0, 0);
outputDevice.Send(ccMsg);
}
}
So from this, I'm really unsure why this wouldn't be working. Perhaps there is another MIDI library I could be using, or perhaps I'm just missing something with respect to how these MIDI devices work.
I developing a Xamarin application, and I communicating an external custom device. My problem is very strange, firstly the application starting, and connecting automatically to device, so everything is fine. When i suddenly remove the battery from the external device, the bluetooth connection is broken, and it's working fine to, but when I turn on the external device again, my Xamarin application connecting to it very well well, but the subscriptions not working anymore.
I debugged it, but not calling anymore. I think the unsubscribe/subscribe process is wrong.
...
if (ble.GetConnectionStatus())
{
Device.BeginInvokeOnMainThread(() =>
{
...
ble.Adapter.DeviceConnectionLost -= Adapter_DeviceConnectionLost;
ble.Adapter.DeviceConnectionLost += Adapter_DeviceConnectionLost;
ble.PropertyChanged -= Ble_PropertyChanged;
ble.PropertyChanged += Ble_PropertyChanged;
data.PropertyChanged -= data_PropertyChanged;
data.PropertyChanged += data_PropertyChanged;
...
});
...
So it's so strange, because first time this working, when starting the app, but when I call it after reconnect that same subscription not working. So if its wrong, then why working this at very first time?
I have no error, just not fire the functions again after resubscribe.
So as you see, I need to "refresh" the subscription. Is there another way to solve this problem?
If that "button to recreate everything" works, then I see two alternatives.
Option 1:
Have such a button, so that user can manually "fix" the situation.
PRO: Gives the user a solution that is guaranteed to work.
CON: Requires user intervention.
Option 2:
Have a periodic timer, that decides whether/when to forcibly "fix" the situation.
PRO: Automatically recovers.
CON: Risks losing data, if forces a recovery at the same time data is arriving.
In pseudo-code, option 2 might be something like this:
// pseudo-code
static Timer timer = ..start a timer that has an event every 10 seconds.
OnTimerElapsed:
if (!eventSeenRecently)
ForceReset();
eventSeenRecently = false;
..whereever you receive data..
if (..has data..)
eventSeenRecently = true;
The concept is that you keep track of whether data continues to be received. If the device stops sending you information (but you believe it should be), then you "ForceReset" - whatever is needed to get everything going again.
DeviceConnectionLost should also set some flag, that you use to ForceReset when the device "comes back".
// pseudo-code
DeviceConnectionLost:
resetNeeded = true;
OnTimerElapsed:
if (resetNeeded && ..test that device is available again..) {
ForceReset();
resetNeeded = false;
}
Perhaps this custom device has some option or info that can help.
For example, there might be a way to query some id or other info, so you can discover that the device is now "different", in a way that requires the reset. Then the timer does that query, and uses that info to decide to reset.
Context
I'm developing a traffic management app using C# (Xamarin Forms) which requires a constant feed of the user's location.
Plugin
I'm using the Geolocator plugin by James Montemagno and the PositionChanged event on the IGeolocator interface seems to be triggering twice when a position change occurs.
Device
I'm currently debugging on an Android Emulator on Visual Studio Enterprise v15.5.3
Steps to reproduce the behaviour
1) After instantiating the locator object:
IGeolocator locator = CrossGeolocator.Current
2) Some code for when the locator's PositionChanged is triggered:
locator.PositionChanged += (sender,e) => {
// Testing its frequency
System.Diagnostics.Debug.WriteLine("Position Changed Triggered.");
}
3) Start listening in an async Task function
locator.DesiredAccuracy = 100;
if(!locator.isListening)
await locator.StartListeningAsync(TimeSpan.FromMilliseconds(500), 1, true);
4) Send coordinates via the emulator
Expected Results
The output window should display one message saying "Position Changed Triggered".
Actual Results
The output window has two identical messages printed, saying: "Position Changed Triggered".
Why is this happening? and how can I make it so that the event is ONLY triggered/handled ONCE for every time the position is actually changed.
What I've tried so far
Googled the issue, not many identical situations found.
Saw an explanation here which makes me believe it's the emulator has something to do with it, although I found the solution a bit ambiguous and am not sure what they're referring to with "Live/Pin Mode"
Created a separate function and assigned the event to it, then removed it after calling my code. This does cause it to execute once, but it never executes again unless I reassign in. And if I do, sure enough the code will run for the second time, resulting in the same initial problem.
Tried setting a boolean to check if it has already run once, but realised not long after how that's illogical.
Tried to set a DateTime object to make sure no more than 1 event occurs in a given time frame; this was also no good.
Help would be appreciated. Thanks.
Please note that the location service might deliver a location event more than one time (more here).
Even if the location service is not delivering the location event more than one time, usage and/or implementation of the API (Geolocator plugin) might cause reception of the location event more than one time from the API.
In the app you might check the location event properties (accuracy, location timestamp, order of event received, etc.). Use the "best" location event with "best" meaning preferred accuracy, most recent timestamp, or the first received location event if timestamp and accuracy are equal.
At the moment I have an app which allows user to send data to a restful webapi, whilst connected to the internet, but this app should also work offline. Thus I am storing user actions in a SQLlite database. This information should be persisted to the webapi when the mobile device finds internet connection.
I have implemented
public bool IsConnected(){
var connectivityManager = (ConnectivityManager)GetSystemService (ConnectivityService);
var activeConnection = connectivityManager.ActiveNetworkInfo;
if ((activeConnection != null) && activeConnection.IsConnected) {
return true;
}
return false;
}
This is called by the OnCreateOptionMenu() of every activity. Which works fine. However when I place a webapi request, which is sadly synchronous call causes the app to display a blank screen until it has processed this. Now this is the user experience I would like to replace with, something similar like ASYNC (asynchronus) request, which works everything in the background without any interruption. But I am struggling to implement this. I did have a Sync button on the app home screen, which onclick ran async call however I do not trust the app users to press this button. Hence I would like to trigger this work in the background. Can someone please advise?
Thank you #MilenPavlov and #CDrosos.
I went with CDrosos's solution as this was ideally what I was looking for.
I created a static timer member in BaseActivity, which on app start is set. This way no concurrencies will occur. This allowed me to create a timer elapsed method which would check database for pending web requests, and post if IsConnected and pendingWebRequests.Any().
if (_timer == null)
{
_timer = new Timer();
_timer.Elapsed += _timer_Elapsed;
_timer.Interval = (1000 * 60) * 5; // 5 ;
_timer.Start();
}
Then make webapi request.
Is it possible to get shutdown reason in Windows Server 2008 immediately after user choose the reason in dialog window? For the shutdown event I'm using SystemEvents.SessionEnding.
I want to write windows service, which will send e-mail about this event.
Or is there any other way in windows server to send e-mails about shutdown/restart event with getting the reason entered by user? Also, I want to notify about power source change (electic line/battery), but this I have already solved by Kernel32.dll > GetSystemPowerStatus.
You can get the shutdown reason inspecting the EventLog.
I assembled a quick demo on Windows Forms that you can adapt to your Windows service.
I've added a EventLog component to the Form and configured it properly. The snippet below shows the code generated in InitializeComponent() for the settings I've maid through the designer.
this.eventLog1.EnableRaisingEvents = true;
this.eventLog1.Log = "System";
this.eventLog1.Source = "USER32";
this.eventLog1.SynchronizingObject = this;
this.eventLog1.EntryWritten += new System.Diagnostics.EntryWrittenEventHandler(this.eventLog1_EntryWritten);
On the event handler, you'll have something along the following lines:
private void eventLog1_EntryWritten(object sender, System.Diagnostics.EntryWrittenEventArgs e)
{
EventLogEntry entry = e.Entry;
if (e.Entry.EventID == 1074)
{
File.AppendAllText(#"c:\message.txt", entry.Message);
}
}
Take a look at your event log to see the appropriate EventIds to filter out.
The compiler will warn you about EventID being deprecated and telling you that you should use InstanceId, but in the quick tests I've done here, it didn't write to my log file and I think we already have enough information to put you on track.
sure it's possible.
in case you want to get that comboBox value in real-time, you will need to run a Thread monitor on that process to raise an event when that value change.